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

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

View File

@@ -0,0 +1,10 @@
BasedOnStyle: Google
BreakBeforeBraces: Linux
AlignConsecutiveDeclarations: true
AlignConsecutiveMacros: true
AlignConsecutiveAssignments: true
AllowShortFunctionsOnASingleLine: Inline
AllowShortIfStatementsOnASingleLine: false
SortIncludes: false
IndentWidth: 4
ColumnLimit: 120

View File

@@ -0,0 +1,4 @@
/test/build/
/test/cmake-build-debug/
/.idea/
/test/

View File

@@ -0,0 +1,31 @@
Tencent is pleased to support the open source community by making IoT Hub available.
Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
If you have downloaded a copy of the IoT Hub binary from Tencent, please note that the IoT Hub binary is licensed under the MIT License.
If you have downloaded a copy of the IoT Hub source code from Tencent, please note that IoT Hub source code is licensed under the MIT License,
except for the third-party components listed below which are subject to different license terms. Your integration of IoT Hub into your own projects may require compliance with the MIT License,
as well as the other licenses applicable to the third-party components included within IoT Hub.
A copy of the MIT License is included in this file.
Open Source Software Licensed under the MIT License: The below software in this distribution may have been modified by Tencent (“Tencent Modifications”). All Tencent Modifications are Copyright (C) 2016 THL A29 Limited.
--------------------------------------------------------------------
1. cpp-feather-ini-parser 1.42
Copyright (c) 2014 Turbine1991
2. Dirent 1.22
Copyright (c) 2015 Toni Rönkkö
Terms of the MIT License:
--------------------------------------------------------------------
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@@ -0,0 +1,74 @@
/*
* 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 1
#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__)
// some sdk info needs to stored on the device and the address is up to you
#define BLE_QIOT_RECORD_FLASH_ADDR 0x3f000
// the following definition will affect the stack that LLSync usedthe minimum value tested is
// 2048BLE_QIOT_EVENT_MAX_SIZE is 128, BLE_QIOT_EVENT_BUF_SIZE is 23 the max length that llsync event data, depends
// on the length of user data reported to Tencent Lianlian at a time
#define BLE_QIOT_EVENT_MAX_SIZE (128)
// the minimum between BLE_QIOT_EVENT_MAX_SIZE and mtu
#define BLE_QIOT_EVENT_BUF_SIZE (23)
#ifdef __cplusplus
}
#endif
#endif // QCLOUD_BLE_QIOT_CONFIG_H

View File

@@ -0,0 +1,123 @@
# 1 概述
本文档介绍如何将 LLSync SDK 移植到目标硬件平台。
# 2 接入指引
一般情况下,各平台接入 LLSync SDK 可以分为两个步骤:
## 2.1 硬件抽象层移植
`ble_qiot_import.h`中列出了所有需要开发者适配的接口,开发者可以参考函数描述在硬件平台上做具体实现。
### 2.1.1 设备接口适配
| 序号 | 函数 | 说明 |
| :--: | :-----------------: | :----------------------------------: |
| 1 | ble_get_product_id | 获取设备三元信息之产品ID |
| 2 | ble_get_device_name | 获取设备三元信息之设备名称 |
| 3 | ble_get_psk | 获取设备三元信息之设备密钥 |
| 4 | ble_get_mac | 获取设备蓝牙MAC地址 |
| 5 | ble_write_flash | SDK 需要存储内部信息到设备存储介质 |
| 6 | ble_read_flash | SDK 需要从设备存储介质读取存储的信息 |
| 7 | 定时器接口 | 定时器类接口 |
1. 设备三元信息在 [物联网开发平台](https://cloud.tencent.com/product/iotexplorer) 新建产品并创建设备后通过 [查看设备信息](https://cloud.tencent.com/document/product/1081/34741#.E6.9F.A5.E7.9C.8B.E8.AE.BE.E5.A4.87.E4.BF.A1.E6.81.AF) 获取。开发者需要负责信息存储,存储介质不做限制,开发阶段可以将三元信息保存在代码中,量产阶段可以将信息存储在片上 flash、片外 flash、eeprom等或带有文件系统的存储介质中方便量产烧录。
2. 不同的蓝牙协议栈获取到的 mac 地址字节序可能不同适配该接口时可能需要进行转换。LLSync 使用大端方式存储,即 mac 地址的第 0 字节存储在低地址mac 地址的第 5 字节存储在高地址,一般与阅读顺序相同。
3. SDK 需要存储约 20 字节数据到 flash 中,存储介质不做限制,存储地址由开发者划分,通过宏`BLE_QIOT_RECORD_FLASH_ADDR`指定若开发者使用文件系统保存SDK数据不涉及存储地址时宏`BLE_QIOT_RECORD_FLASH_ADDR`可设置为 0。
4. ble_write_flash() 接口只负责数据写入擦除、读写平衡等需由开发者在合适的时机进行例如在写入前进行擦除写入完成后回收旧page等。
5. 当使用定时广播功能时,需要实现定时器类接口。若不使用定时广播功能,定时器类接口可以实现为桩函数。
### 2.1.2 BLE 协议栈适配
| 序号 | 函数 | 说明 |
| :--: | :------------------------: | :-----------------------------: |
| 1 | ble_services_add | 添加 LLSync 服务到 BLE 协议栈 |
| 2 | ble_advertising_start | 开始广播接口 |
| 2 | ble_advertising_stop | 停止广播接口 |
| 4 | ble_send_notify | 向 UUID FFE3写入通知 |
| 5 | ble_get_user_data_mtu_size | 获取向 UUID FFE3 写入数据的最大长度 |
1. LLsync SDK 定义了若干 BLE attribute characteristicLLSync SDK 初始化时会调用 ble_services_add() 将其加入 BLE 协议栈。具体服务可以通过 ble_qiot_export.h 的 ble_get_qiot_services() 获取。如果蓝牙协议栈不支持动态添加蓝牙服务,也可以参考 `service_info` 结构体静态蓝牙服务。对于每一个attribute characteristic value max length开发者需要保证大于等于蓝牙协议栈支持的mtu大小以免造成数据丢失、指针越界等问题。
2. LLSync 规定了广播数据的格式,开发者需要通过 BLE 协议栈将传入的数据广播出去,微信小程序依赖广播数据发现并连接设备。广播数据包含两种类型,分别是 `0x02 <Partial list of 16 bit service UUIDs>``0x03 <Complete list of 16 bit service UUIDs>``0xFF < Manufacturer Specific Data>`
3. 开发者可以根据实际情况选择使用 `0x02``0x03` 类型广播UUIDUUID中必须包含 `#define IOT_BLE_UUID_SERVICE 0xFFE0`,如有需开发者也可以加入自己私有的 service UUID。
4. Manufacturer Specific Data 广播类型包含 company identifier在内一共为 17 字节。如果开发者需要广播设备名等其他信息,只使用广播包很可能放不下,此时可以使用广播扫描回应包携带更多广播数据。
5. LLSync 规定了数据的最大长度为2048字节SDK 实现了数据的分片发送,连续多次调用`ble_send_notify`将数据发送出去。SDK 内没有做数据重传处理,因此开发者需要保证数据的发送成功。
## 2.2 数据模版代码生成
1. 开发者在物联网开发平台创建设备,定义 [数据模版](https://cloud.tencent.com/document/product/1081/34916)
2. 通过脚本将数据模版转换为C代码
```c
iot@iot-MB0 scripts % python3 interpret_json_dt/src/interpret_dt_ble.py interpret_json_dt/example.json
reading json file start
reading json file end
generate header file start
generate header file end
generate source file start
generate source file end
```
3. 拷贝生成的`ble_qiot_template.c`和`ble_qiot_template.h`到用户代码文件夹。
# 3 应用开发
## 3.1 SDK配置
拷贝`ble_qiot_config.h`到用户代码文件夹,并做简单配置。
1. `BLE_QIOT_RECORD_FLASH_ADDR`是 SDK 数据的存储地址。
2. `__BYTE_ORDER__`是设备的大小端定义。
3. SDK 支持定时广播。定义`BLE_QIOT_BUTTON_BROADCAST`为1当设备在未绑定状态下开始广播时经过`BLE_QIOT_BUTTON_BROADCAST`定义的时间后广播自动停止。设备处于绑定状态时不支持定时广播功能。
4. 适配 SDK 的log输出接口 `#define BLE_QIOT_LOG_PRINT(...) printf(__VA_ARGS__)`,根据实际情况将 printf 替换为自己的打印函数。由于部分蓝牙协议栈特殊的缓存机制LLSync SDK 提供的 ble_qiot_log_hex() 可能无法正常工作,请将宏 `#define BLE_QIOT_USER_DEFINE_HEDUMP 0` 打开,由用户自己实现 ble_qiot_log_hex() 接口。
5. `BLE_QIOT_EVENT_MAX_SIZE`定义了设备端可以通过notify发送的最大数据量用户可以通过减小此数值来优化堆栈。经测试`BLE_QIOT_EVENT_MAX_SIZE`配置为128`BLE_QIOT_EVENT_BUF_SIZE`配置为23时栈内存占用2k不到。
6. `BLE_QIOT_EVENT_BUF_SIZE`配置为`BLE_QIOT_EVENT_MAX_SIZE`和MTU的最小值。
## 3.2 例程代码抽取
SDK 已经适配了多个硬件平台,例程代码存储在`samples/nrf52832`目录下。开发者可以通过脚本将指定硬件平台的例程抽取出来,将抽取后的代码加入硬件平台进行编译。以`nordic 52832`示例:
```c
iot@iot-MB0 code_extract % python3 code_extract.py nrf52832
extract code for nrf52832 start, dest dir /iot/Desktop/work_code/qcloud_iot_explorer_ble/scripts/code_extract/qcloud-iot-ble-nrf52832
extract code success
```
一般的,例程代码中会提供相应的`readme.md`文档说明如何编译。
## 3.3 数据模版开发
例程中`data_template`目录下包含了数据模版文件和转换后的 C 代码模版,开发者可以进行参考。
1. 对于数据模版中的`propertyies`C 代码模版中给每个`id`生成了`ble_property_xxx_set`和`ble_property_xxx_get`两个接口。SDK 收到服务器下发的数据后通过`ble_property_xxx_set`传递给用户,开发者接收数据后进行处理。`ble_property_xxx_get`用于获取设备上的数据SDK 负责将其上报到服务器。在`sg_ble_property_array`中定义了每个`id`的属性。
2. 对于数据模版中的`events`,每个`event`有若干个`param`C 代码模版中给每个`param`生成了一个`ble_event_get_xxx`接口用于获取设备上的数据SDK 负责将其上报到服务器。在`sg_ble_event_array`中定义了每个`event`的属性,每个`event`也有一个数组用来描述其包含的所有`param`的属性。
3. 对于数据模版中的`actions`,每个`action`有若干个`inputid`和`outputid``inputid`中定义了服务器下发的数据,`outputid`中定义了设备上报的数据C 代码模版中给每个`action`生成了`ble_action_handle_xxx_input_cb`和`ble_action_handle_xxx_output_cb`两个接口。SDK 收到服务器下发的数据后通过`ble_action_handle_xxx_input_cb`传递给用户,开发者接收数据后进行处理,处理结束后 SDK 通过`ble_action_handle_xxx_output_cb`获取用户反馈的数据上报到服务器。在`sg_ble_action_array`中定义了每个`action`的属性。
一般约定,用户数据以网络序进行传递,所以开发者需要做字节序转换。
## 3.4 API说明
在`ble_qiot_export.h`中提供了 API 函数,一般情况下用户只需要调用 API 函数即可完成应用开发。
| 序号 | 函数 | 说明 |
| :--: | :------------------------: | :----------------------------------------------------------: |
| 1 | ble_qiot_explorer_init | SDK 初始化 |
| 2 | ble_event_get_status | 获取数据模版最新信息,对应数据模版`get_status`方法 |
| 3 | ble_event_report_property | 上报设备最新信息,对应数据模版`report`方法 |
| 4 | ble_event_post | 上报事件,对应数据模版`event_post`方法 |
| 5 | ble_qiot_advertising_start | 开始广播,广播包内容请参考 ble_advertising_start |
| 6 | ble_qiot_advertising_stop | 停止广播 |
| 7 | ble_device_info_write_cb | UUID FFE1数据到达后调用此接口传入数据 |
| 8 | ble_lldata_write_cb | UUID FFE2数据到达后调用此接口传入数据 |
| 9 | ble_get_qiot_services | 获取需要加入协议栈的蓝牙服务 |
| 10 | ble_gap_connect_cb | 蓝牙设备连接时调用此接口通知SDK |
| 11 | ble_gap_disconnect_cb | 蓝牙设备断开连接时调用此接口通知SDK |
# 4 LLSync 协议
请参见《LLSync蓝牙设备接入协议.pdf》
# 5 物联网开发平台使用帮助
参见 https://cloud.tencent.com/document/product/1081

View File

@@ -0,0 +1,167 @@
/*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
* Licensed under the MIT License (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://opensource.org/licenses/MIT
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#ifndef QCLOUD_BLE_QIOT_EXPORT_H
#define QCLOUD_BLE_QIOT_EXPORT_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include "ble_qiot_common.h"
// Tencent Company ID
#define TENCENT_COMPANY_IDENTIFIER 0xFEE7
#define TENCENT_COMPANY_IDENTIFIER2 0xFEBA
#define IOT_BLE_UUID_BASE \
{ \
0xe2, 0xa4, 0x1b, 0x54, 0x93, 0xe4, 0x6a, 0xb5, 0x20, 0x4e, 0xd0, 0x65, 0x00, 0x00, 0x00, 0x00 \
}
// llsync services uuid
#define IOT_BLE_UUID_SERVICE 0xFFE0
// characteristics uuid
#define IOT_BLE_UUID_DEVICE_INFO 0xFFE1 // used to connection and identity authentication
#define IOT_BLE_UUID_DATA 0xFFE2 // used to send data to the device from server
#define IOT_BLE_UUID_EVENT 0xFFE3 // used to send data to the server from device
typedef enum {
GATT_CHAR_BROADCAST = (1 << 0), // Broadcasting of the value permitted.
GATT_CHAR_READ = (1 << 1), // Reading the value permitted.
GATT_CHAR_WRITE_WO_RESP = (1 << 2), // Writing the value with Write Command permitted.
GATT_CHAR_WRITE = (1 << 3), // Writing the value with Write Request permitted.
GATT_CHAR_NOTIFY = (1 << 4), // Notification of the value permitted.
GATT_CHAR_INDICATE = (1 << 5), // Indications of the value permitted.
GATT_CHAR_AUTH_SIGNED_WR = (1 << 6), // Writing the value with Signed Write Command permitted.
} char_props_s;
// the callback function prototype definition for the characteristics
typedef void (*ble_on_write_cb)(const uint8_t *buf, uint16_t len);
// the characteristics attributes
typedef struct {
uint16_t uuid16;
uint8_t gatt_char_props;
ble_on_write_cb on_write;
} qiot_char_s;
// the service attributes
typedef struct {
uint16_t service_uuid16;
uint8_t service_uuid128[16];
uint16_t gatt_max_mtu;
qiot_char_s device_info;
qiot_char_s data;
qiot_char_s event;
} qiot_service_init_s;
typedef enum {
BLE_QIOT_RS_OK = 0, // success
BLE_QIOT_RS_ERR = -1, // normal error
BLE_QIOT_RS_ERR_FLASH = -2, // flash error
BLE_QIOT_RS_ERR_PARA = -3, // parameters error
BLE_QIOT_RS_VALID_SIGN_ERR = -4,
} ble_qiot_ret_status_t;
/**
* @brief get llsync services context
*
* @return llsync services struct
*/
const qiot_service_init_s *ble_get_qiot_services(void);
/**
* @brief llsync sdck initialize
* @note you should called it before any other sdk api
* @return BLE_QIOT_RS_OK is success, other is error
*/
ble_qiot_ret_status_t ble_qiot_explorer_init(void);
/**
* @brief get property of the device from the server
* @note the property will be received from IOT_BLE_UUID_DATA if success
* @return BLE_QIOT_RS_OK is success, other is error. if success, the data from server will come to
*/
ble_qiot_ret_status_t ble_event_get_status(void);
/**
* @brief report property of the device to the server
* @note the reply will be received from IOT_BLE_UUID_DATA if success
* @return BLE_QIOT_RS_OK is success, other is error
*/
ble_qiot_ret_status_t ble_event_report_property(void);
/**
* @brief report mtu of the device to the server
* @note report mtu to the server for optimizing bandwidth usage. this mtu equals (ATT_MTU - 3)
* @return BLE_QIOT_RS_OK is success, other is error
*/
ble_qiot_ret_status_t ble_event_report_device_info(void);
/**
* @brief post event to the server
* @param event_id id of the event
* @note the reply will be received from IOT_BLE_UUID_DATA if success
* @return BLE_QIOT_RS_OK is success, other is error
*/
ble_qiot_ret_status_t ble_event_post(uint8_t event_id);
/**
* @brief start llsync advertising
* @note broadcast data according to the device bind state, reference to llsync protocol
* @return BLE_QIOT_RS_OK is success, other is error
*/
ble_qiot_ret_status_t ble_qiot_advertising_start(void);
/**
* @brief stop advertising
* @return BLE_QIOT_RS_OK is success, other is error
*/
ble_qiot_ret_status_t ble_qiot_advertising_stop(void);
/**
* @brief device info write callbcak, call the function when characteristic IOT_BLE_UUID_DEVICE_INFO received data
* @param buf a pointer point to the data
* @param len data length
* @return none
*/
void ble_device_info_write_cb(const uint8_t *buf, uint16_t len);
/**
* @brief data write callback, call the function when characteristic IOT_BLE_UUID_DATA received data
* @param buf a pointer point to the data
* @param len data length
* @return none
*/
void ble_lldata_write_cb(const uint8_t *buf, uint16_t len);
/**
* @brief gap event connect call-back, when gap get ble connect event, use this function
* tell qiot ble sdk
* @return none
*/
void ble_gap_connect_cb(void);
/**
* @brief gap event disconnect call-back, when gap get ble disconnect event, use this function
* tell qiot ble sdk
* @return none
*/
void ble_gap_disconnect_cb(void);
#ifdef __cplusplus
}
#endif
#endif // QCLOUD_BLE_QIOT_EXPORT_H

View File

@@ -0,0 +1,167 @@
/*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
* Licensed under the MIT License (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://opensource.org/licenses/MIT
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#ifndef QCLOUD_BLE_QIOT_IMPORT_H
#define QCLOUD_BLE_QIOT_IMPORT_H
#if defined(__cplusplus)
extern "C" {
#endif
#include <stdint.h>
#include "ble_qiot_export.h"
// 16 bits service UUIDs list, use advertising type 0x02 or 0x03
typedef struct
{
uint8_t uuid_num;
uint16_t *uuids;
} uuid_list_s;
// advertise manufacture specific data, use advertising type 0xFF
typedef struct
{
uint16_t company_identifier;
uint8_t *adv_data;
uint8_t adv_data_len;
} manufacturer_data_s;
typedef struct {
uuid_list_s uuid_info;
manufacturer_data_s manufacturer_info;
} adv_info_s;
/**
* @brief get device product id
* @param product_id the buf storage product id, 10 bytes permanent
* @return 0 is success, other is error
*/
int ble_get_product_id(char *product_id);
/**
* @brief get device name
* @param device_name the buf storage device name, the max length of the device name is 48 bytes
* @return length of device name, 0 is error
*/
int ble_get_device_name(char *device_name);
/**
* @brief get device secret
* @param psk the buf storage secret, 24 bytes permanent
* @return 0 is success, other is error
*/
int ble_get_psk(char *psk);
/**
* @brief get mac address
* @param mac the buf storage mac, 6 bytes permanent
* @return 0 is success, other is error
*/
int ble_get_mac(char *mac);
/**
* @brief write data to flash
* @param flash_addr write address in flash
* @param write_buf point to write buf
* @param write_len length of data to write
* @return write_len is success, other is error
*/
int ble_write_flash(uint32_t flash_addr, const char *write_buf, uint16_t write_len);
/**
* @brief read data from flash
* @param flash_addr read address from flash
* @param read_buf point to read buf
* @param read_len length of data to read
* @return read_len is success, other is error
*/
int ble_read_flash(uint32_t flash_addr, char *read_buf, uint16_t read_len);
/**
* @brief add llsync services to ble stack
* @param qiot_service_init_s llsync service
* @return none
*/
void ble_services_add(const qiot_service_init_s *p_service);
/**
* @brief start llsync advertising
* @param adv a pointer point to advertising data
* @return BLE_QIOT_RS_OK is success, other is error
*/
ble_qiot_ret_status_t ble_advertising_start(adv_info_s *adv);
/**
* @brief stop advertising
* @return BLE_QIOT_RS_OK is success, other is error
*/
ble_qiot_ret_status_t ble_advertising_stop(void);
/**
* @brief send a notification to host, use characteristic IOT_BLE_UUID_EVENT
* @param buf a pointer point to indication information
* @param len indication information length
* @return BLE_QIOT_RS_OK is success, other is error
*/
ble_qiot_ret_status_t ble_send_notify(uint8_t *buf, uint8_t len);
/**
* @brief get the max size of data that user can used, normally is ATT_MTU - 3
* @return the value
*/
uint16_t ble_get_user_data_mtu_size(void);
// timer type
enum {
BLE_TIMER_ONE_SHOT_TYPE = 0,
BLE_TIMER_PERIOD_TYPE,
BLE_TIMER_BUTT,
};
typedef void *ble_timer_t;
// timer callback prototype
typedef void (*ble_timer_cb)(void *param);
/**
* @brief create a timer
* @param type timer type
* @param timeout_handle timer callback
* @return timer identifier is return, NULL is error
*/
ble_timer_t ble_timer_create(uint8_t type, ble_timer_cb timeout_handle);
/**
* @brief start a timer
* @param timer_id Timer identifier
* @param period timer period(unit: ms)
* @return BLE_QIOT_RS_OK is success, other is error
*/
ble_qiot_ret_status_t ble_timer_start(ble_timer_t timer_id, uint32_t period);
/**
* @brief stop a timer
* @param timer_id Timer identifier
* @return BLE_QIOT_RS_OK is success, other is error
*/
ble_qiot_ret_status_t ble_timer_stop(ble_timer_t timer_id);
/**
* @brief delete a timer
* @param timer_id Timer identifier
* @return BLE_QIOT_RS_OK is success, other is error
*/
ble_qiot_ret_status_t ble_timer_delete(ble_timer_t timer_id);
#if defined(__cplusplus)
}
#endif
#endif // QCLOUD_BLE_QIOT_IMPORT_H

View File

@@ -0,0 +1,48 @@
## 概述
LLSync SDK 提供了 LLSync 协议接入方案SDK 内实现了 LLSync 协议用于和 APP(网关设备)进行通信,打通了 `BLE设备-APP(网关设备)-物联网开发平台` 的数据链路,支持开发者快速接入 BLE 设备到物联网开发平台。开发者接入 LLSync SDK需要做的工作有
1. 添加 LLSync Service到 BLE 协议栈中
2. 通过脚本将数据模版转换为C代码添加相应的数据处理
LLSync SDK 封装了协议实现细节和数据传输过程,让开发者可以聚焦在数据处理上,以达到快速开发的目的。
## 软件架构
LLSync SDK 结构框图:
![LLSync结构框图](https://main.qcloudimg.com/raw/9fabb2c222ae40d6a93641b745a327bd.png)
SDK 分三层设计从上至下分别为应用层、LLSync核心层、HAL移植层。
* 应用层LLSync SDK 生成了数据模版的模版文件,用户需要根据需求做具体实现。
* LLSync 核心组件:实现了 BLE 设备和App (网关设备)之间的通信协议,身份认证,数据解析等功能,用户一般无需改动即可使用。
* HAL 移植层:主要是适配 BLE 协议栈,用户需要进行移植和适配。
## 目录结构
```c
qcloud_iot_explorer_ble
config # SDK
docs #
inc #
samples #
esp32 # esp32例程
lifesense # apollo3 blue例程
nrf52832 # nordic 52832
scripts #
code_extract #
interpret_json_dt #
config # ini文件
src #
dt_fixed_content # C代码中的固定内容
src # LLSync源码
core #
internal_inc #
utils #
```
## 移植指引
请参见 LLSync SDK接入指引.md

View File

@@ -0,0 +1,6 @@
# The following lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(llsync)

View File

@@ -0,0 +1,28 @@
if (CONFIG_QCLOUD_LLSYNC_SUPPORT)
set(srcs
src/core/ble_qiot_llsync_data.c
src/core/ble_qiot_llsync_device.c
src/core/ble_qiot_llsync_event.c
src/core/ble_qiot_service.c
src/utils/ble_qiot_utils_base64.c
src/utils/ble_qiot_utils_hmac.c
src/utils/ble_qiot_utils_log.c
src/utils/ble_qiot_utils_md5.c
src/utils/ble_qiot_utils_sha1.c)
list(APPEND srcs
date_template/ble_qiot_template.c)
list(APPEND srcs
hal/ble_qiot_ble_device.c
hal/ble_qiot_ble_service.c)
set(includes inc src/internal_inc)
set(priv_includes date_template src/internal_inc hal)
endif ()
idf_component_register(SRCS "${srcs}"
INCLUDE_DIRS "${includes}"
PRIV_INCLUDE_DIRS "${priv_includes}"
REQUIRES bt)

View File

@@ -0,0 +1,7 @@
menu "QCloud LLSync"
config QCLOUD_LLSYNC_SUPPORT
bool "QCloud LLSync support."
default "y"
endmenu

View File

@@ -0,0 +1,149 @@
/*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
* Licensed under the MIT License (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://opensource.org/licenses/MIT
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#ifdef __cplusplus
extern "C" {
#endif
#include "ble_qiot_template.h"
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include "ble_qiot_export.h"
#include "ble_qiot_common.h"
#include "ble_qiot_param_check.h"
float sg_ch20_ppm = 0.0;
static int ble_property_ch20_ppm_value_set(const char *data, uint16_t len)
{
return 0;
}
static int ble_property_ch20_ppm_value_get(char *data, uint16_t buf_len)
{
memcpy(data, &sg_ch20_ppm, sizeof(float));
return sizeof(float);
}
static ble_property_t sg_ble_property_array[BLE_QIOT_PROPERTY_ID_BUTT] = {
{ble_property_ch20_ppm_value_set, ble_property_ch20_ppm_value_get, BLE_QIOT_PROPERTY_AUTH_READ,
BLE_QIOT_DATA_TYPE_FLOAT},
};
static bool ble_check_space_enough_by_type(uint8_t type, uint16_t left_size)
{
switch (type) {
case BLE_QIOT_DATA_TYPE_BOOL:
return left_size >= sizeof(uint8_t);
case BLE_QIOT_DATA_TYPE_INT:
case BLE_QIOT_DATA_TYPE_FLOAT:
case BLE_QIOT_DATA_TYPE_TIME:
return left_size >= sizeof(uint32_t);
case BLE_QIOT_DATA_TYPE_ENUM:
return left_size >= sizeof(uint16_t);
default:
// string length is unknow, default true
return true;
}
}
static uint16_t ble_check_ret_value_by_type(uint8_t type, uint16_t buf_len, uint16_t ret_val)
{
switch (type) {
case BLE_QIOT_DATA_TYPE_BOOL:
return ret_val <= sizeof(uint8_t);
case BLE_QIOT_DATA_TYPE_INT:
case BLE_QIOT_DATA_TYPE_FLOAT:
case BLE_QIOT_DATA_TYPE_TIME:
return ret_val <= sizeof(uint32_t);
case BLE_QIOT_DATA_TYPE_ENUM:
return ret_val <= sizeof(uint16_t);
default:
// string length is unknow, default true
return ret_val <= buf_len;
}
}
uint8_t ble_get_property_type_by_id(uint8_t id)
{
if (id >= BLE_QIOT_PROPERTY_ID_BUTT) {
ble_qiot_log_e("invalid property id %d", id);
return BLE_QIOT_DATA_TYPE_BUTT;
}
return sg_ble_property_array[id].type;
}
int ble_user_property_set_data(const e_ble_tlv *tlv)
{
POINTER_SANITY_CHECK(tlv, BLE_QIOT_RS_ERR_PARA);
if (tlv->id >= BLE_QIOT_PROPERTY_ID_BUTT) {
ble_qiot_log_e("invalid property id %d", tlv->id);
return BLE_QIOT_RS_ERR;
}
if (NULL != sg_ble_property_array[tlv->id].set_cb) {
if (0 != sg_ble_property_array[tlv->id].set_cb(tlv->val, tlv->len)) {
ble_qiot_log_e("set property id %d failed", tlv->id);
return BLE_QIOT_RS_ERR;
} else {
return BLE_QIOT_RS_OK;
}
}
ble_qiot_log_e("invalid set callback, id %d", tlv->id);
return BLE_QIOT_RS_ERR;
}
int ble_user_property_get_data_by_id(uint8_t id, char *buf, uint16_t buf_len)
{
int ret_len = 0;
POINTER_SANITY_CHECK(buf, BLE_QIOT_RS_ERR_PARA);
if (id >= BLE_QIOT_PROPERTY_ID_BUTT) {
ble_qiot_log_e("invalid property id %d", id);
return -1;
}
if (NULL != sg_ble_property_array[id].get_cb) {
if (!ble_check_space_enough_by_type(sg_ble_property_array[id].type, buf_len)) {
ble_qiot_log_e("not enough space get property id %d data", id);
return -1;
}
ret_len = sg_ble_property_array[id].get_cb(buf, buf_len);
if (ret_len < 0) {
ble_qiot_log_e("get property id %d data failed", id);
return -1;
} else {
if (ble_check_ret_value_by_type(sg_ble_property_array[id].type, buf_len, ret_len)) {
return ret_len;
} else {
ble_qiot_log_e("property id %d length invalid", id);
return -1;
}
}
}
ble_qiot_log_e("invalid callback, property id %d", id);
return 0;
}
int ble_user_property_report_reply_handle(uint8_t result)
{
ble_qiot_log_d("report reply result %d", result);
return BLE_QIOT_RS_OK;
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,163 @@
/*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
* Licensed under the MIT License (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://opensource.org/licenses/MIT
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#ifndef BLE_QIOT_TEMPLATE_H_
#define BLE_QIOT_TEMPLATE_H_
#ifdef __cplusplus
extern "C"{
#endif
#include <stdint.h>
// data type in template, corresponding to type in json file
enum {
BLE_QIOT_DATA_TYPE_BOOL = 0,
BLE_QIOT_DATA_TYPE_INT,
BLE_QIOT_DATA_TYPE_STRING,
BLE_QIOT_DATA_TYPE_FLOAT,
BLE_QIOT_DATA_TYPE_ENUM,
BLE_QIOT_DATA_TYPE_TIME,
BLE_QIOT_DATA_TYPE_BUTT,
};
// message type, reference data template
enum {
BLE_QIOT_MSG_TYPE_PROPERTY = 0,
BLE_QIOT_MSG_TYPE_EVENT,
BLE_QIOT_MSG_TYPE_ACTION,
BLE_QIOT_MSG_TYPE_BUTT,
};
// define property authority, not used
enum {
BLE_QIOT_PROPERTY_AUTH_RW = 0,
BLE_QIOT_PROPERTY_AUTH_READ,
BLE_QIOT_PROPERTY_AUTH_BUTT,
};
// define reply result
enum {
BLE_QIOT_REPLY_SUCCESS = 0,
BLE_QIOT_REPLY_FAIL,
BLE_QIOT_REPLY_DATA_ERR,
BLE_QIOT_REPLY_BUTT,
};
// define message flow direction
enum {
BLE_QIOT_EFFECT_REQUEST = 0,
BLE_QIOT_EFFECT_REPLY,
BLE_QIOT_EFFECT_BUTT,
};
// define message type that from server to device
enum {
BLE_QIOT_DATA_DOWN_REPORT_REPLY = 0,
BLE_QIOT_DATA_DOWN_CONTROL,
BLE_QIOT_DATA_DOWN_GET_STATUS_REPLY,
BLE_QIOT_DATA_DOWN_ACTION,
BLE_QIOT_DATA_DOWN_EVENT_REPLY,
};
// define message type that from device to server
enum {
BLE_QIOT_EVENT_UP_PROPERTY_REPORT = 0,
BLE_QIOT_EVENT_UP_CONTROL_REPLY,
BLE_QIOT_EVENT_UP_GET_STATUS,
BLE_QIOT_EVENT_UP_EVENT_POST,
BLE_QIOT_EVENT_UP_ACTION_REPLY,
BLE_QIOT_EVENT_UP_BIND_SIGN_RET,
BLE_QIOT_EVENT_UP_CONN_SIGN_RET,
BLE_QIOT_EVENT_UP_UNBIND_SIGN_RET,
BLE_QIOT_EVENT_UP_REPORT_MTU,
BLE_QIOT_EVENT_UP_BUTT,
};
// msg header define, bit 7-6 is msg type, bit 5 means request or reply, bit 4 - 0 is id
#define BLE_QIOT_PARSE_MSG_HEAD_TYPE(_C) (((_C) & 0XFF) >> 6)
#define BLE_QIOT_PARSE_MSG_HEAD_EFFECT(_C) ((((_C) & 0XFF) & 0X20) ? BLE_QIOT_EFFECT_REPLY : BLE_QIOT_EFFECT_REQUEST)
#define BLE_QIOT_PARSE_MSG_HEAD_ID(_C) ((_C) & 0X1F)
#define BLE_QIOT_PACKAGE_MSG_HEAD(_TYPE, _REPLY, _ID) (((_TYPE) << 6) | (((_REPLY) == BLE_QIOT_EFFECT_REPLY) << 5) | ((_ID) & 0X1F))
// tlv header define, bit 7 - 5 is type, bit 4 - 0 depends on type of data template
#define BLE_QIOT_PARSE_TLV_HEAD_TYPE(_C) (((_C) & 0XFF) >> 5)
#define BLE_QIOT_PARSE_TLV_HEAD_ID(_C) ((_C) & 0X1F)
#define BLE_QIOT_PACKAGE_TLV_HEAD(_TYPE, _ID) (((_TYPE) << 5) | ((_ID) & 0X1F))
// define tlv struct
typedef struct{
uint8_t type;
uint8_t id;
uint16_t len;
char *val;
}e_ble_tlv;
#define BLE_QIOT_INCLUDE_PROPERTY
// define property id
enum {
BLE_QIOT_PROPERTY_ID_CH20_PPM_VALUE = 0,
BLE_QIOT_PROPERTY_ID_BUTT,
};
// define ch20_ppm_value attributes
#define BLE_QIOT_PROPERTY_CH20_PPM_VALUE_MIN (0)
#define BLE_QIOT_PROPERTY_CH20_PPM_VALUE_MAX (2)
#define BLE_QIOT_PROPERTY_CH20_PPM_VALUE_START (0)
#define BLE_QIOT_PROPERTY_CH20_PPM_VALUE_STEP (0.001)
// define property set handle return 0 if success, other is error
// sdk call the function that inform the server data to the device
typedef int (*property_set_cb)(const char *data, uint16_t len);
// define property get handle. return the data length obtained, -1 is error, 0 is no data
// sdk call the function fetch user data and send to the server, the data should wrapped by user adn skd just transmit
typedef int (*property_get_cb)(char *buf, uint16_t buf_len);
// each property have a struct ble_property_t, make up a array named sg_ble_property_array
typedef struct{
property_set_cb set_cb; //set callback
property_get_cb get_cb; //get callback
uint8_t authority; //property authority
uint8_t type; //data type
}ble_property_t;
// property module
#ifdef BLE_QIOT_INCLUDE_PROPERTY
uint8_t ble_get_property_type_by_id(uint8_t id);
int ble_user_property_set_data(const e_ble_tlv *tlv);
int ble_user_property_get_data_by_id(uint8_t id, char *buf, uint16_t buf_len);
int ble_user_property_report_reply_handle(uint8_t result);
#endif
// event module
#ifdef BLE_QIOT_INCLUDE_EVENT
int ble_event_get_id_array_size(uint8_t event_id);
uint8_t ble_event_get_param_id_type(uint8_t event_id, uint8_t param_id);
int ble_event_get_data_by_id(uint8_t event_id, uint8_t param_id, char *out_buf, uint16_t buf_len);
int ble_user_event_reply_handle(uint8_t event_id, uint8_t result);
#endif
// action module
#ifdef BLE_QIOT_INCLUDE_ACTION
uint8_t ble_action_get_intput_type_by_id(uint8_t action_id, uint8_t input_id);
uint8_t ble_action_get_output_type_by_id(uint8_t action_id, uint8_t output_id);
int ble_action_get_input_id_size(uint8_t action_id);
int ble_action_get_output_id_size(uint8_t action_id);
int ble_action_user_handle_input_param(uint8_t action_id, e_ble_tlv *input_param_array, uint8_t input_array_size, uint8_t *output_id_array);
int ble_action_user_handle_output_param(uint8_t action_id, uint8_t output_id, char *buf, uint16_t buf_len);
#endif
#ifdef __cplusplus
}
#endif
#endif //BLE_QIOT_TEMPLATE_H_

View File

@@ -0,0 +1,26 @@
{
"version": "1.0",
"profile": {
"ProductId": "1NBPCQ7L2O",
"CategoryId": "1"
},
"properties": [
{
"id": "ch20_ppm_value",
"name": "甲醛浓度值",
"desc": "",
"mode": "r",
"define": {
"type": "float",
"min": "0",
"max": "2",
"start": "0",
"step": "0.001",
"unit": "ppm(mg/m3)"
},
"required": false
}
],
"events": [],
"actions": []
}

View File

@@ -0,0 +1,114 @@
/*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
* Licensed under the MIT License (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://opensource.org/licenses/MIT
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#ifdef __cplusplus
extern "C" {
#endif
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include "ble_qiot_export.h"
#include "ble_qiot_service.h"
#include "ble_qiot_import.h"
// add std head file here
#include <stdint.h>
// add ble qiot head file here
#include "ble_qiot_import.h"
#include "ble_qiot_config.h"
#include "esp_bt_device.h"
#include "esp_spi_flash.h"
// divece info which defined in explorer platform
#define PRODUCT_ID "1NBPCQ7L2O"
#define DEVICE_NAME "123"
#define SECRET_KEY "q/WQFemC2ejNZTNWMqHerA=="
int ble_get_product_id(char *product_id)
{
memcpy(product_id, PRODUCT_ID, strlen(PRODUCT_ID));
return 0;
}
int ble_get_device_name(char *device_name)
{
memcpy(device_name, DEVICE_NAME, strlen(DEVICE_NAME));
return strlen(DEVICE_NAME);
}
int ble_get_psk(char *psk)
{
memcpy(psk, SECRET_KEY, strlen(SECRET_KEY));
return 0;
}
int ble_get_mac(char *mac)
{
char *address = (char *)esp_bt_dev_get_address();
memcpy(mac, address, 6);
return 0;
}
int ble_write_flash(uint32_t flash_addr, const char *write_buf, uint16_t write_len)
{
int ret = spi_flash_erase_range(flash_addr, BLE_QIOT_RECORD_FLASH_PAGESIZE);
ret = spi_flash_write(flash_addr, write_buf, write_len);
return ret == ESP_OK ? write_len : ret;
}
int ble_read_flash(uint32_t flash_addr, char *read_buf, uint16_t read_len)
{
int ret = spi_flash_read(flash_addr, read_buf, read_len);
return ret == ESP_OK ? read_len : ret;
}
ble_timer_t ble_timer_create(uint8_t type, ble_timer_cb timeout_handle)
{
return NULL;
}
ble_qiot_ret_status_t ble_timer_start(ble_timer_t timer_id, uint32_t period)
{
return BLE_QIOT_RS_OK;
}
ble_qiot_ret_status_t ble_timer_stop(ble_timer_t timer_id)
{
return BLE_QIOT_RS_OK;
}
ble_qiot_ret_status_t ble_timer_delete(ble_timer_t timer_id)
{
return BLE_QIOT_RS_OK;
}
// should return ATT_MTU - 3
uint16_t ble_get_user_data_mtu_size(void)
{
// esp32 can not get mtuuse default mtu
return 20;
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,536 @@
/*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
* Licensed under the MIT License (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://opensource.org/licenses/MIT
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#ifdef __cplusplus
extern "C" {
#endif
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "esp_bt.h"
#include "esp_gap_ble_api.h"
#include "esp_gatts_api.h"
#include "esp_bt_main.h"
#include "esp_gatt_common_api.h"
#include "ble_qiot_config.h"
#include "ble_qiot_export.h"
#include "ble_qiot_service.h"
#include "ble_qiot_import.h"
#define LLSYNC_LOG_TAG "LLSYNC"
/* Attributes State Machine */
enum
{
IDX_SVC,
IDX_CHAR_A,
IDX_CHAR_VAL_A,
IDX_CHAR_B,
IDX_CHAR_VAL_B,
IDX_CHAR_C,
IDX_CHAR_VAL_C,
IDX_CHAR_CFG_C,
HRS_IDX_NB,
};
#define PROFILE_NUM 1
#define PROFILE_APP_IDX 0
#define LLSYNC_APP_ID 0x55
#define SAMPLE_DEVICE_NAME "l"
#define SVC_INST_ID 0
/* The max length of characteristic value. When the GATT client performs a write or prepare write operation,
* the data length must be less than LLSYNC_CHAR_VAL_LEN_MAX.
*/
#define LLSYNC_CHAR_VAL_LEN_MAX 500
#define PREPARE_BUF_MAX_SIZE 1024
#define CHAR_DECLARATION_SIZE (sizeof(uint8_t))
#define ADV_CONFIG_FLAG (1 << 0)
static uint8_t adv_config_done = 0;
uint16_t llsync_handle_table[HRS_IDX_NB];
typedef struct {
uint8_t *prepare_buf;
int prepare_len;
uint16_t handle;
} prepare_type_env_t;
static prepare_type_env_t prepare_write_env;
static uint8_t raw_adv_data[32] = {
/* flags */
0x02, 0x01, 0x06,
/* service uuid */
0x03, 0x03, 0xE0, 0xFF,
};
static esp_ble_adv_params_t adv_params = {
.adv_int_min = 0x20,
.adv_int_max = 0x40,
.adv_type = ADV_TYPE_IND,
.own_addr_type = BLE_ADDR_TYPE_PUBLIC,
.channel_map = ADV_CHNL_ALL,
.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY,
};
struct gatts_profile_inst {
esp_gatts_cb_t gatts_cb;
uint16_t gatts_if;
uint16_t app_id;
uint16_t conn_id;
uint16_t service_handle;
esp_gatt_srvc_id_t service_id;
uint16_t char_handle;
esp_bt_uuid_t char_uuid;
esp_gatt_perm_t perm;
esp_gatt_char_prop_t property;
uint16_t descr_handle;
esp_bt_uuid_t descr_uuid;
};
ble_qiot_ret_status_t ble_advertising_start(adv_info_s *adv)
{
uint8_t usr_adv_data[31] = {0};
uint8_t len = 0;
uint8_t index = 0;
memcpy(usr_adv_data, &adv->manufacturer_info.company_identifier, sizeof(uint16_t));
len = sizeof(uint16_t);
memcpy(usr_adv_data + len, adv->manufacturer_info.adv_data, adv->manufacturer_info.adv_data_len);
len += adv->manufacturer_info.adv_data_len;
index = 7;
raw_adv_data[index++] = len + 1;
raw_adv_data[index++] = 0xFF;
memcpy(raw_adv_data + index, usr_adv_data, len);
index += len;
raw_adv_data[index++] = strlen(SAMPLE_DEVICE_NAME) + 1;
raw_adv_data[index++] = 0x09;
memcpy(raw_adv_data + index, SAMPLE_DEVICE_NAME, strlen(SAMPLE_DEVICE_NAME));
index += strlen(SAMPLE_DEVICE_NAME);
esp_log_buffer_hex("adv", raw_adv_data, index);
//config adv data
esp_err_t ret = esp_ble_gap_config_adv_data_raw(raw_adv_data, index);
if (ret) {
ESP_LOGE(LLSYNC_LOG_TAG, "config adv data failed, error code = %x", ret);
}
adv_config_done |= ADV_CONFIG_FLAG;
ESP_LOGI(LLSYNC_LOG_TAG, "start advertising");
esp_ble_gap_start_advertising(&adv_params);
return 0;
}
ble_qiot_ret_status_t ble_advertising_stop(void)
{
esp_ble_gap_stop_advertising();
return 0;
}
static void gatts_profile_event_handler(esp_gatts_cb_event_t event,
esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param);
/* One gatt-based profile one app_id and one gatts_if, this array will store the gatts_if returned by ESP_GATTS_REG_EVT */
static struct gatts_profile_inst llsync_profile_tab[PROFILE_NUM] = {
[PROFILE_APP_IDX] = {
.gatts_cb = gatts_profile_event_handler,
.gatts_if = ESP_GATT_IF_NONE, /* Not get the gatt_if, so initial is ESP_GATT_IF_NONE */
},
};
ble_qiot_ret_status_t ble_send_notify(uint8_t *buf, uint8_t len)
{
esp_ble_gatts_send_indicate(llsync_profile_tab[PROFILE_APP_IDX].gatts_if, llsync_profile_tab[PROFILE_APP_IDX].conn_id,
llsync_handle_table[IDX_CHAR_VAL_C],len, buf, false);
return BLE_QIOT_RS_OK;
}
static const uint16_t primary_service_uuid = ESP_GATT_UUID_PRI_SERVICE;
static const uint16_t character_declaration_uuid = ESP_GATT_UUID_CHAR_DECLARE;
static const uint16_t character_client_config_uuid = ESP_GATT_UUID_CHAR_CLIENT_CONFIG;
static const uint8_t char_prop_write = ESP_GATT_CHAR_PROP_BIT_WRITE;
static const uint8_t char_prop_notify = ESP_GATT_CHAR_PROP_BIT_NOTIFY;
static const uint8_t heart_measurement_ccc[2] = {0x00, 0x00};
/* service_uuid and Characteristic_uuid*/
static uint8_t llsync_service_uuid[16] = {
0xe2, 0xa4, 0x1b, 0x54, 0x93, 0xe4, 0x6a, 0xb5, 0x20, 0x4e, 0xd0, 0x65, 0xe0, 0xff, 0x00, 0x00,
};
static uint8_t llsync_device_info_uuid[16] = {
0xe2, 0xa4, 0x1b, 0x54, 0x93, 0xe4, 0x6a, 0xb5, 0x20, 0x4e, 0xd0, 0x65, 0xe1, 0xff, 0x00, 0x00,
};
static uint8_t llsync_data_uuid[16] = {
0xe2, 0xa4, 0x1b, 0x54, 0x93, 0xe4, 0x6a, 0xb5, 0x20, 0x4e, 0xd0, 0x65, 0xe2, 0xff, 0x00, 0x00,
};
static uint8_t llsync_event_uuid[16] = {
0xe2, 0xa4, 0x1b, 0x54, 0x93, 0xe4, 0x6a, 0xb5, 0x20, 0x4e, 0xd0, 0x65, 0xe3, 0xff, 0x00, 0x00,
};
/* Full Database Description - Used to add attributes into the database */
static const esp_gatts_attr_db_t gatt_db[HRS_IDX_NB] =
{
// Service Declaration
[IDX_SVC] =
{{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&primary_service_uuid, ESP_GATT_PERM_READ,
sizeof(llsync_service_uuid), sizeof(llsync_service_uuid), (uint8_t *)llsync_service_uuid}},
/* Characteristic Declaration */
[IDX_CHAR_A] =
{{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_declaration_uuid, ESP_GATT_PERM_READ,
CHAR_DECLARATION_SIZE, CHAR_DECLARATION_SIZE, (uint8_t *)&char_prop_write}},
/* Characteristic Value */
[IDX_CHAR_VAL_A] =
{{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_128, (uint8_t *)llsync_device_info_uuid, ESP_GATT_PERM_WRITE,
LLSYNC_CHAR_VAL_LEN_MAX, 0, NULL}},
/* Characteristic Declaration */
[IDX_CHAR_B] =
{{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_declaration_uuid, ESP_GATT_PERM_READ,
CHAR_DECLARATION_SIZE, CHAR_DECLARATION_SIZE, (uint8_t *)&char_prop_write}},
/* Characteristic Value */
[IDX_CHAR_VAL_B] =
{{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_128, (uint8_t *)llsync_data_uuid, ESP_GATT_PERM_WRITE,
LLSYNC_CHAR_VAL_LEN_MAX, 0, NULL}},
/* Characteristic Declaration */
[IDX_CHAR_C] =
{{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_declaration_uuid, ESP_GATT_PERM_READ,
CHAR_DECLARATION_SIZE, CHAR_DECLARATION_SIZE, (uint8_t *)&char_prop_notify}},
/* Characteristic Value */
[IDX_CHAR_VAL_C] =
{{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_128, (uint8_t *)llsync_event_uuid, 0,
LLSYNC_CHAR_VAL_LEN_MAX, 0, NULL}},
/* Characteristic User Descriptor */
[IDX_CHAR_CFG_C] =
{{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_client_config_uuid, ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE,
sizeof(uint16_t), sizeof(heart_measurement_ccc), (uint8_t *)heart_measurement_ccc}},
};
static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param)
{
switch (event) {
case ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT:
ESP_LOGI(LLSYNC_LOG_TAG, "ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT");
adv_config_done &= (~ADV_CONFIG_FLAG);
if (adv_config_done == 0) {
ble_qiot_advertising_start();
adv_config_done = 2;
}
break;
case ESP_GAP_BLE_ADV_START_COMPLETE_EVT:
/* advertising start complete event to indicate advertising start successfully or failed */
if (param->adv_start_cmpl.status != ESP_BT_STATUS_SUCCESS) {
ESP_LOGE(LLSYNC_LOG_TAG, "advertising start failed");
}else{
ESP_LOGI(LLSYNC_LOG_TAG, "advertising start successfully");
}
break;
case ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT:
if (param->adv_stop_cmpl.status != ESP_BT_STATUS_SUCCESS) {
ESP_LOGE(LLSYNC_LOG_TAG, "Advertising stop failed");
}
else {
ESP_LOGI(LLSYNC_LOG_TAG, "Stop adv successfully\n");
}
break;
case ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT:
ESP_LOGI(LLSYNC_LOG_TAG, "update connection params status = %d, min_int = %d, max_int = %d,conn_int = %d,latency = %d, timeout = %d",
param->update_conn_params.status,
param->update_conn_params.min_int,
param->update_conn_params.max_int,
param->update_conn_params.conn_int,
param->update_conn_params.latency,
param->update_conn_params.timeout);
break;
default:
break;
}
}
void example_prepare_write_event_env(esp_gatt_if_t gatts_if, prepare_type_env_t *prepare_write_env, esp_ble_gatts_cb_param_t *param)
{
ESP_LOGI(LLSYNC_LOG_TAG, "prepare write, handle = %d, value len = %d", param->write.handle, param->write.len);
esp_gatt_status_t status = ESP_GATT_OK;
if (prepare_write_env->prepare_buf == NULL) {
prepare_write_env->prepare_buf = (uint8_t *)malloc(PREPARE_BUF_MAX_SIZE * sizeof(uint8_t));
prepare_write_env->prepare_len = 0;
prepare_write_env->handle = 0;
if (prepare_write_env->prepare_buf == NULL) {
ESP_LOGE(LLSYNC_LOG_TAG, "%s, Gatt_server prep no mem", __func__);
status = ESP_GATT_NO_RESOURCES;
}
} else {
if(param->write.offset > PREPARE_BUF_MAX_SIZE) {
status = ESP_GATT_INVALID_OFFSET;
} else if ((param->write.offset + param->write.len) > PREPARE_BUF_MAX_SIZE) {
status = ESP_GATT_INVALID_ATTR_LEN;
}
}
/*send response when param->write.need_rsp is true */
if (param->write.need_rsp){
esp_gatt_rsp_t *gatt_rsp = (esp_gatt_rsp_t *)malloc(sizeof(esp_gatt_rsp_t));
if (gatt_rsp != NULL){
gatt_rsp->attr_value.len = param->write.len;
gatt_rsp->attr_value.handle = param->write.handle;
gatt_rsp->attr_value.offset = param->write.offset;
gatt_rsp->attr_value.auth_req = ESP_GATT_AUTH_REQ_NONE;
memcpy(gatt_rsp->attr_value.value, param->write.value, param->write.len);
esp_err_t response_err = esp_ble_gatts_send_response(gatts_if, param->write.conn_id, param->write.trans_id, status, gatt_rsp);
if (response_err != ESP_OK){
ESP_LOGE(LLSYNC_LOG_TAG, "Send response error");
}
free(gatt_rsp);
}else{
ESP_LOGE(LLSYNC_LOG_TAG, "%s, malloc failed", __func__);
}
}
if (status != ESP_GATT_OK){
return;
}
memcpy(prepare_write_env->prepare_buf + param->write.offset,
param->write.value,
param->write.len);
prepare_write_env->prepare_len += param->write.len;
prepare_write_env->handle = param->write.handle;
}
void example_exec_write_event_env(prepare_type_env_t *prepare_write_env, esp_ble_gatts_cb_param_t *param){
if (param->exec_write.exec_write_flag == ESP_GATT_PREP_WRITE_EXEC && prepare_write_env->prepare_buf){
if (prepare_write_env->handle == llsync_handle_table[IDX_CHAR_VAL_A]){
ESP_LOGI(LLSYNC_LOG_TAG, "ble_device_info_write_cb");
ble_device_info_write_cb(prepare_write_env->prepare_buf, prepare_write_env->prepare_len);
}else if (prepare_write_env->handle == llsync_handle_table[IDX_CHAR_VAL_B]){
ESP_LOGI(LLSYNC_LOG_TAG, "ble_lldata_write_cb");
ble_lldata_write_cb(prepare_write_env->prepare_buf, prepare_write_env->prepare_len);
}
esp_log_buffer_hex(LLSYNC_LOG_TAG, prepare_write_env->prepare_buf, prepare_write_env->prepare_len);
}else{
ESP_LOGI(LLSYNC_LOG_TAG,"ESP_GATT_PREP_WRITE_CANCEL");
}
if (prepare_write_env->prepare_buf) {
free(prepare_write_env->prepare_buf);
prepare_write_env->prepare_buf = NULL;
}
prepare_write_env->prepare_len = 0;
}
static void gatts_profile_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param)
{
switch (event) {
case ESP_GATTS_REG_EVT:
{
esp_err_t set_dev_name_ret = esp_ble_gap_set_device_name(SAMPLE_DEVICE_NAME);
if (set_dev_name_ret) {
ESP_LOGE(LLSYNC_LOG_TAG, "set device name failed, error code = %x", set_dev_name_ret);
}
esp_err_t raw_adv_ret = esp_ble_gap_config_adv_data_raw(raw_adv_data, 7);
if (raw_adv_ret){
ESP_LOGE(LLSYNC_LOG_TAG, "config raw adv data failed, error code = %x ", raw_adv_ret);
}
adv_config_done |= ADV_CONFIG_FLAG;
esp_err_t create_attr_ret = esp_ble_gatts_create_attr_tab(gatt_db, gatts_if, HRS_IDX_NB, SVC_INST_ID);
if (create_attr_ret) {
ESP_LOGE(LLSYNC_LOG_TAG, "create attr table failed, error code = %x", create_attr_ret);
}
}
break;
case ESP_GATTS_READ_EVT:
ESP_LOGI(LLSYNC_LOG_TAG, "ESP_GATTS_READ_EVT");
break;
case ESP_GATTS_WRITE_EVT:
if (!param->write.is_prep){
// the data length of gattc write must be less than LLSYNC_CHAR_VAL_LEN_MAX.
ESP_LOGI(LLSYNC_LOG_TAG, "GATT_WRITE_EVT, handle = %d, value len = %d, value :", param->write.handle, param->write.len);
esp_log_buffer_hex(LLSYNC_LOG_TAG, param->write.value, param->write.len);
if (param->write.handle == llsync_handle_table[IDX_CHAR_VAL_A]){
ESP_LOGI(LLSYNC_LOG_TAG, "ble_device_info_write_cb");
ble_device_info_write_cb(param->write.value, param->write.len);
}else if (param->write.handle == llsync_handle_table[IDX_CHAR_VAL_B]){
ESP_LOGI(LLSYNC_LOG_TAG, "ble_lldata_write_cb");
ble_lldata_write_cb(param->write.value, param->write.len);
}
ESP_LOGI(LLSYNC_LOG_TAG, "GATT_WRITE_EVT OVER");
/* send response when param->write.need_rsp is true*/
if (param->write.need_rsp){
esp_ble_gatts_send_response(gatts_if, param->write.conn_id, param->write.trans_id, ESP_GATT_OK, NULL);
}
}else{
example_prepare_write_event_env(gatts_if, &prepare_write_env, param);
}
break;
case ESP_GATTS_EXEC_WRITE_EVT:
// the length of gattc prepare write data must be less than GATTS_DEMO_CHAR_VAL_LEN_MAX.
ESP_LOGI(LLSYNC_LOG_TAG, "ESP_GATTS_EXEC_WRITE_EVT");
example_exec_write_event_env(&prepare_write_env, param);
break;
case ESP_GATTS_MTU_EVT:
ESP_LOGI(LLSYNC_LOG_TAG, "ESP_GATTS_MTU_EVT, MTU %d", param->mtu.mtu);
break;
case ESP_GATTS_CONF_EVT:
ESP_LOGI(LLSYNC_LOG_TAG, "ESP_GATTS_CONF_EVT, status = %d, attr_handle %d", param->conf.status, param->conf.handle);
break;
case ESP_GATTS_START_EVT:
ESP_LOGI(LLSYNC_LOG_TAG, "SERVICE_START_EVT, status %d, service_handle %d", param->start.status, param->start.service_handle);
break;
case ESP_GATTS_CONNECT_EVT:
ESP_LOGI(LLSYNC_LOG_TAG, "ESP_GATTS_CONNECT_EVT, conn_id = %d", param->connect.conn_id);
esp_log_buffer_hex(LLSYNC_LOG_TAG, param->connect.remote_bda, 6);
esp_ble_conn_update_params_t conn_params = {0};
memcpy(conn_params.bda, param->connect.remote_bda, sizeof(esp_bd_addr_t));
/* For the iOS system, please refer to Apple official documents about the BLE connection parameters restrictions. */
conn_params.latency = 0;
conn_params.max_int = 0x20; // max_int = 0x20*1.25ms = 40ms
conn_params.min_int = 0x10; // min_int = 0x10*1.25ms = 20ms
conn_params.timeout = 400; // timeout = 400*10ms = 4000ms
//start sent the update connection parameters to the peer device.
esp_ble_gap_update_conn_params(&conn_params);
break;
case ESP_GATTS_DISCONNECT_EVT:
ESP_LOGI(LLSYNC_LOG_TAG, "ESP_GATTS_DISCONNECT_EVT, reason = 0x%x", param->disconnect.reason);
ble_qiot_advertising_start();
break;
case ESP_GATTS_CREAT_ATTR_TAB_EVT:{
if (param->add_attr_tab.status != ESP_GATT_OK){
ESP_LOGE(LLSYNC_LOG_TAG, "create attribute table failed, error code=0x%x", param->add_attr_tab.status);
}
else if (param->add_attr_tab.num_handle != HRS_IDX_NB){
ESP_LOGE(LLSYNC_LOG_TAG, "create attribute table abnormally, num_handle (%d) doesn't equal to HRS_IDX_NB(%d)", param->add_attr_tab.num_handle, HRS_IDX_NB);
}
else {
ESP_LOGI(LLSYNC_LOG_TAG, "create attribute table successfully, the number handle = %d\n",param->add_attr_tab.num_handle);
memcpy(llsync_handle_table, param->add_attr_tab.handles, sizeof(llsync_handle_table));
esp_ble_gatts_start_service(llsync_handle_table[IDX_SVC]);
}
break;
}
case ESP_GATTS_STOP_EVT:
case ESP_GATTS_OPEN_EVT:
case ESP_GATTS_CANCEL_OPEN_EVT:
case ESP_GATTS_CLOSE_EVT:
case ESP_GATTS_LISTEN_EVT:
case ESP_GATTS_CONGEST_EVT:
case ESP_GATTS_UNREG_EVT:
case ESP_GATTS_DELETE_EVT:
default:
break;
}
}
static void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param)
{
/* If event is register event, store the gatts_if for each profile */
if (event == ESP_GATTS_REG_EVT) {
if (param->reg.status == ESP_GATT_OK) {
llsync_profile_tab[PROFILE_APP_IDX].gatts_if = gatts_if;
} else {
ESP_LOGE(LLSYNC_LOG_TAG, "reg app failed, app_id %04x, status %d", param->reg.app_id, param->reg.status);
return;
}
}
do {
int idx;
for (idx = 0; idx < PROFILE_NUM; idx++) {
/* ESP_GATT_IF_NONE, not specify a certain gatt_if, need to call every profile cb function */
if (gatts_if == ESP_GATT_IF_NONE || gatts_if == llsync_profile_tab[idx].gatts_if) {
if (llsync_profile_tab[idx].gatts_cb) {
llsync_profile_tab[idx].gatts_cb(event, gatts_if, param);
}
}
}
} while (0);
}
void ble_services_add(const qiot_service_init_s *p_service)
{
// do nothing
return;
}
void ble_qiot_service_init(void)
{
esp_err_t ret;
ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT));
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
ret = esp_bt_controller_init(&bt_cfg);
if (ret) {
ESP_LOGE(LLSYNC_LOG_TAG, "%s enable controller failed: %s", __func__, esp_err_to_name(ret));
return;
}
ret = esp_bt_controller_enable(ESP_BT_MODE_BLE);
if (ret) {
ESP_LOGE(LLSYNC_LOG_TAG, "%s enable controller failed: %s", __func__, esp_err_to_name(ret));
return;
}
ret = esp_bluedroid_init();
if (ret) {
ESP_LOGE(LLSYNC_LOG_TAG, "%s init bluetooth failed: %s", __func__, esp_err_to_name(ret));
return;
}
ret = esp_bluedroid_enable();
if (ret) {
ESP_LOGE(LLSYNC_LOG_TAG, "%s enable bluetooth failed: %s", __func__, esp_err_to_name(ret));
return;
}
// init llsync sdk
ble_qiot_explorer_init();
ret = esp_ble_gatts_register_callback(gatts_event_handler);
if (ret){
ESP_LOGE(LLSYNC_LOG_TAG, "gatts register error, error code = %x", ret);
return;
}
ret = esp_ble_gap_register_callback(gap_event_handler);
if (ret){
ESP_LOGE(LLSYNC_LOG_TAG, "gap register error, error code = %x", ret);
return;
}
ret = esp_ble_gatts_app_register(LLSYNC_APP_ID);
if (ret){
ESP_LOGE(LLSYNC_LOG_TAG, "gatts app register error, error code = %x", ret);
return;
}
return;
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,71 @@
/*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
* Licensed under the MIT License (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://opensource.org/licenses/MIT
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#ifndef QCLOUD_BLE_QIOT_CONFIG_H
#define QCLOUD_BLE_QIOT_CONFIG_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdio.h>
#include <stdint.h>
#include "esp_log.h"
#define BLE_QIOT_SDK_VERSION "1.2.0" // sdk version
#define BLE_QIOT_SDK_DEBUG 0 // sdk debug switch
// the device broadcast is controlled by the user, but we provide a mechanism to help the device save more power.
// if you want broadcast is triggered by something like press a button instead of all the time, and the broadcast
// stopped automatically in a few minutes if the device is not bind, define BLE_QIOT_BUTTON_BROADCAST is 1 and
// BLE_QIOT_BIND_TIMEOUT is the period that broadcast stopped.
// if the device in the bound state, broadcast dose not stop automatically.
#define BLE_QIOT_BUTTON_BROADCAST 0
#if (1 == BLE_QIOT_BUTTON_BROADCAST)
#define BLE_QIOT_BIND_TIMEOUT (2 * 60 * 1000) // unit: ms
#endif
// some data like integer need to be transmitted in a certain byte order, defined it according to your device
#define __ORDER_LITTLE_ENDIAN__ 1234
#define __ORDER_BIG_ENDIAN__ 4321
#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__
// in some BLE stack ble_qiot_log_hex() maybe not work, user can use there own hexdump function
#define BLE_QIOT_USER_DEFINE_HEDUMP 1
#if (1 == BLE_QIOT_USER_DEFINE_HEDUMP)
#define ble_qiot_log_hex(level, hex_name, data, data_len) \
do { \
esp_log_buffer_hex(hex_name, data, data_len); \
} while (0)
#endif // BLE_QIOT_USER_DEFINE_HEDUMP
// Macro for logging a formatted string, the function must printf raw string without any color, prefix, newline or
// timestamp
#define BLE_QIOT_LOG_PRINT(...) printf(__VA_ARGS__)
// nrf52832xxAA Flash size is 512KB, nrf52832xxAB Flash size is 512KB, be carefol of the address!
#define BLE_QIOT_RECORD_FLASH_ADDR 0xFE000 // qiot data storage address
#define BLE_QIOT_RECORD_FLASH_PAGESIZE 4096 // flash page size, see chip datasheet
// the following definition will affect the stack that LLSync usedthe minimum value tested is
// 2048BLE_QIOT_EVENT_MAX_SIZE is 128, BLE_QIOT_EVENT_BUF_SIZE is 23 the max length that llsync event data, depends
// on the length of user data reported to Tencent Lianlian at a time
#define BLE_QIOT_EVENT_MAX_SIZE (128)
// the minimum between BLE_QIOT_EVENT_MAX_SIZE and mtu
#define BLE_QIOT_EVENT_BUF_SIZE (23)
#ifdef __cplusplus
}
#endif
#endif // QCLOUD_BLE_QIOT_CONFIG_H

View File

@@ -0,0 +1 @@
idf_component_register(SRCS "app_main.c" INCLUDE_DIRS "")

View File

@@ -0,0 +1,54 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2017 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP32 only, in which case,
* it is free of charge, to any person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or
* substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "ble_qiot_export.h"
extern void ble_qiot_service_init(void);
extern float sg_ch20_ppm;
static void test_task(void *pvParameters)
{
while (1) {
sg_ch20_ppm += 0.001;
printf("report ppm %.3f\n", sg_ch20_ppm);
ble_event_report_property();
vTaskDelay(10000 / portTICK_PERIOD_MS);
}
}
void app_main()
{
nvs_flash_init();
ble_qiot_service_init();
xTaskCreate(test_task, "tsk1", 4 * 1024, NULL, 5, NULL);
}

View File

@@ -0,0 +1,6 @@
# Name, Type, SubType, Offset, Size
phy_init, data, phy, 0xf000, 0x1000
otadata,data,ota, 0x10000, 8K
nvs,data,nvs, 0x12000, 56K
ota_0,app, ota_0, 0x100000,0x180000
ota_1,app, ota_1, 0x280000,0x180000
1 # Name Type SubType Offset Size
2 phy_init data phy 0xf000 0x1000
3 otadata data ota 0x10000 8K
4 nvs data nvs 0x12000 56K
5 ota_0 app ota_0 0x100000 0x180000
6 ota_1 app ota_1 0x280000 0x180000

View File

@@ -0,0 +1,36 @@
## 说明
本工程模拟了一个甲醛监测场景ESP32任务定期模拟甲醛数据(也可以通过甲醛监测传感器实时获取)ESP32通过BLE和腾讯连连小程序连接使用LLSync协议传输数据由腾讯连连小程序将甲醛数据上传到物联网开发平台。
## 使用说明
1. 安装`ESP-IDF`,请参考[官网文档](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-started/index.html#step-2-get-esp-idf)
```c
mkdir -p ~/esp
cd ~/esp
git clone --recursive https://github.com/espressif/esp-idf.git
```
2. 抽取`qcloud-iot-ble-esp32`组件
```c
cd scripts
python3 code_extract/code_extract.py esp32
```
3. 拷贝`qcloud-iot-ble-esp32`组件到`ESP-IDF`目录下
```c
cp -r scripts/code_extract/qcloud-iot-ble-esp32 $IDF_PATH
cd $IDF_PATH/qcloud-iot-ble-esp32
```
4. 登陆[物联网开发平台](https://cloud.tencent.com/product/iotexplorer), 使用`qcloud_llsync/date_template/esp32.json`作为数据模版创建设备。
使用新设备的三元信息替换`qcloud_llsync/hal/ble_qiot_ble_device.c`中宏定义中的设备信息,编译并烧录到开发板。
```c
idf.py flash
```
5. 打开腾讯连连小程序,添加设备,观察串口输出和小程序界面,串口输出如下:
```c
report ppm 0.028
I (271165) post data: 00 00 05 60 43 60 e5 3c
I (271165) LLSYNC: ESP_GATTS_CONF_EVT, status = 0, attr_handle 46
I (271445) LLSYNC: GATT_WRITE_EVT, handle = 44, value len = 2, value :
I (271445) LLSYNC: 20 00
I (271445) LLSYNC: ble_lldata_write_cb
I (271445) LLSYNC: GATT_WRITE_EVT OVER
```
可以观察到小程序界面甲醛数据同步变化。

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,485 @@
/*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
* Licensed under the MIT License (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://opensource.org/licenses/MIT
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#ifdef __cplusplus
extern "C" {
#endif
#include "ble_qiot_template.h"
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include "ble_qiot_export.h"
#include "ble_qiot_common.h"
#include "ble_qiot_utils_base64.h"
#include "ble_qiot_param_check.h"
// ignore property power switch,
static int ble_property_power_switch_set(const char *data, uint16_t len)
{
return 0;
}
static int ble_property_power_switch_get(char *data, uint16_t buf_len)
{
return 0;
}
// ignore heart rate set function, cause its read-only
static int ble_property_heart_rate_set(const char *data, uint16_t len)
{
return 0;
}
static int32_t sg_heart_rate = 128;
static int ble_property_heart_rate_get(char *data, uint16_t buf_len)
{
// get your heart rate and copy to the buf which data pointed
// you must convert to network order if the data type is int or enum
int32_t heart_rate = HTONL(sg_heart_rate);
memcpy(data, &heart_rate, sizeof(int32_t));
// if get data success, return the length of data. must 4 bytes for int type
// if get data error, return -1
// if the data no need report, just return 0
return sizeof(uint32_t);
}
// ignore blood oxygen set function, cause its read-only
static int ble_property_blood_oxygen_set(const char *data, uint16_t len)
{
return 0;
}
static int32_t sg_blood_oxygen = 96;
static int ble_property_blood_oxygen_get(char *data, uint16_t buf_len)
{
// copy your blood_oxygen to data
int32_t blood_oxygen = HTONL(sg_blood_oxygen);
memcpy(data, &blood_oxygen, sizeof(int32_t));
return sizeof(uint32_t);
}
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_heart_rate_set, ble_property_heart_rate_get, BLE_QIOT_PROPERTY_AUTH_READ, BLE_QIOT_DATA_TYPE_INT},
{ble_property_blood_oxygen_set, ble_property_blood_oxygen_get, BLE_QIOT_PROPERTY_AUTH_READ, BLE_QIOT_DATA_TYPE_INT},
};
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)
{
POINTER_SANITY_CHECK(buf, BLE_QIOT_RS_ERR_PARA);
if (NULL != sg_ble_property_array[id].get_cb) {
return sg_ble_property_array[id].get_cb(buf, buf_len);
}
ble_qiot_log_e("invalid get callback, property id %d", id);
return 0;
}
int ble_user_property_report_reply_handle(uint8_t result)
{
ble_qiot_log_d("report reply result %d", result);
return BLE_QIOT_RS_OK;
}
//of course you can get all param data, here is just a sample and i'm a bit lazy, so i set some event param return 0 means no data to report
static int ble_event_get_sleep_report_total_sleep_time(char *data, uint16_t buf_len)
{
return 0;
}
static int32_t sg_falling_asleep_time = 1599557269;
static int ble_event_get_sleep_report_falling_asleep_time(char *data, uint16_t buf_len)
{
int32_t time = 0;
time = HTONL(sg_falling_asleep_time);
ble_qiot_log_i("time %d", time);
memcpy(data, &time, sizeof(int32_t));
return sizeof(uint32_t);
}
static int ble_event_get_sleep_report_wakeup_time(char *data, uint16_t buf_len)
{
return 0;
}
static int ble_event_get_sleep_report_deep_sleep_time(char *data, uint16_t buf_len)
{
return 0;
}
static int ble_event_get_sleep_report_light_sleep_time(char *data, uint16_t buf_len)
{
return 0;
}
static int32_t sg_sleep_score = 64;
static int ble_event_get_sleep_report_sleep_score(char *data, uint16_t buf_len)
{
int32_t score = 0;
score = HTONL(sg_sleep_score);
ble_qiot_log_i("score %d", score);
memcpy(data, &score, sizeof(int32_t));
return sizeof(uint32_t);
}
static ble_event_param sg_ble_event_sleep_report_array[BLE_QIOT_EVENT_SLEEP_REPORT_PARAM_ID_BUTT] = {
{ble_event_get_sleep_report_total_sleep_time, BLE_QIOT_DATA_TYPE_INT},
{ble_event_get_sleep_report_falling_asleep_time, BLE_QIOT_DATA_TYPE_TIME},
{ble_event_get_sleep_report_wakeup_time, BLE_QIOT_DATA_TYPE_TIME},
{ble_event_get_sleep_report_deep_sleep_time, BLE_QIOT_DATA_TYPE_INT},
{ble_event_get_sleep_report_light_sleep_time, BLE_QIOT_DATA_TYPE_INT},
{ble_event_get_sleep_report_sleep_score, BLE_QIOT_DATA_TYPE_INT},
};
typedef struct sleep_data_{
int time;
uint8_t state;
uint8_t rsv;
}__attribute__((packed))sleep_data;
static int ble_event_get_sleep_data_data(char *data, uint16_t buf_len)
{
int i = 0;
sleep_data user_data;
int base_time = 1599555600; // 2020/9/8 17:00:00
int ret_len = 0;
char base64_out_buf[16] = {0};
size_t base64_out_len = 0;
for (i = 0; i < 60; i++){
user_data.time = HTONL(base_time + i * 60); // 1 minute time step
user_data.state = 1; // light sleep
user_data.rsv = 0;
#if 1 == BLE_QIOT_POST_BASE64
memset(base64_out_buf, 0, sizeof(base64_out_buf));
base64_out_len = 0;
if (BLE_QIOT_RS_OK != qcloud_iot_utils_base64encode((uint8_t *)base64_out_buf, sizeof(base64_out_buf), &base64_out_len, (const uint8_t *)&user_data, sizeof(user_data))){
ble_qiot_log_e("event base64 failed");
return -1;
}
memcpy(data + ret_len, base64_out_buf, base64_out_len);
ret_len += base64_out_len;
#else
memcpy(data + ret_len, &user_data, sizeof(user_data));
ret_len += sizeof(user_data);
#endif
}
ble_qiot_log_e("ret_len %d, base64_out_len %d", ret_len, base64_out_len);
return ret_len;
}
static ble_event_param sg_ble_event_sleep_data_array[BLE_QIOT_EVENT_SLEEP_DATA_PARAM_ID_BUTT] = {
{ble_event_get_sleep_data_data, BLE_QIOT_DATA_TYPE_STRING},
};
static int ble_event_get_heart_rate_data_data(char *data, uint16_t buf_len)
{
return 0;
}
static ble_event_param sg_ble_event_heart_rate_data_array[BLE_QIOT_EVENT_HEART_RATE_DATA_PARAM_ID_BUTT] = {
{ble_event_get_heart_rate_data_data, BLE_QIOT_DATA_TYPE_STRING},
};
static int ble_event_get_blood_oxygen_data_data(char *data, uint16_t buf_len)
{
return 0;
}
static ble_event_param sg_ble_event_blood_oxygen_data_array[BLE_QIOT_EVENT_BLOOD_OXYGEN_DATA_PARAM_ID_BUTT] = {
{ble_event_get_blood_oxygen_data_data, BLE_QIOT_DATA_TYPE_STRING},
};
static int ble_event_get_today_activity_data(char *data, uint16_t buf_len)
{
return 0;
}
static ble_event_param sg_ble_event_today_activity_array[BLE_QIOT_EVENT_TODAY_ACTIVITY_PARAM_ID_BUTT] = {
{ble_event_get_today_activity_data, BLE_QIOT_DATA_TYPE_STRING},
};
static ble_event_t sg_ble_event_array[BLE_QIOT_EVENT_ID_BUTT] = {
{sg_ble_event_sleep_report_array, sizeof(sg_ble_event_sleep_report_array) / sizeof(ble_event_param)},
{sg_ble_event_sleep_data_array, sizeof(sg_ble_event_sleep_data_array) / sizeof(ble_event_param)},
{sg_ble_event_heart_rate_data_array, sizeof(sg_ble_event_heart_rate_data_array) / sizeof(ble_event_param)},
{sg_ble_event_blood_oxygen_data_array, sizeof(sg_ble_event_blood_oxygen_data_array) / sizeof(ble_event_param)},
{sg_ble_event_today_activity_array, sizeof(sg_ble_event_today_activity_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)
{
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 -1;
}
return sg_ble_event_array[event_id].event_array[param_id].get_cb(out_buf, buf_len);
}
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;
}
bool ble_check_space_enough_by_type(uint8_t type, uint32_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;
}
}
typedef struct read_property{
uint16_t property_id;
uint16_t val;
}__attribute__((packed))read_property;
static int sg_read_property_id = 0;
static int ble_action_handle_read_property_input_cb(e_ble_tlv *input_param_array, uint8_t input_array_size, uint8_t *output_id_array)
{
int i = 0;
int result = 0;
for (i = 0; i < input_array_size; i++){
ble_qiot_log_d("input id %d", input_param_array[i].id);
}
memcpy(&result, input_param_array[0].val, sizeof(int));
sg_read_property_id = NTOHL(result);
// if the input tirger
output_id_array[BLE_QIOT_ACTION_READ_PROPERTY_OUTPUT_ID_VALUE] = true;
return 0;
}
static int ble_action_handle_read_property_output_cb(uint8_t output_id, char *buf, uint16_t buf_len)
{
read_property user_data;
uint8_t base64_out_buf[16] = {0};
size_t base64_out_len = 0;
int ret_len = 0;
if (BLE_QIOT_PROPERTY_ID_HEART_RATE == sg_read_property_id){
uint16_t heart_rate = sg_heart_rate;
user_data.property_id = HTONS(sg_read_property_id);
user_data.val = HTONS(heart_rate);
}else{
uint16_t blood_oxygen = sg_blood_oxygen;
user_data.property_id = HTONS(sg_read_property_id);
user_data.val = HTONS(blood_oxygen);
}
#if 1 == BLE_QIOT_POST_BASE64
memset(base64_out_buf, 0, sizeof(base64_out_buf));
if (BLE_QIOT_RS_OK != qcloud_iot_utils_base64encode((uint8_t *)base64_out_buf, sizeof(base64_out_buf), &base64_out_len, (const uint8_t *)&user_data, sizeof(user_data))){
ble_qiot_log_e("action base64 failed");
return -1;
}
memcpy(buf, base64_out_buf, base64_out_len);
ret_len = base64_out_len;
#else
memcpy(buf , &user_data, sizeof(user_data));
ret_len = sizeof(user_data);
#endif
return ret_len;
}
static uint8_t sg_ble_action_read_property_input_type_array[BLE_QIOT_ACTION_READ_PROPERTY_INPUT_ID_BUTT] = {
BLE_QIOT_DATA_TYPE_INT,
};
static uint8_t sg_ble_action_read_property_output_type_array[BLE_QIOT_ACTION_READ_PROPERTY_OUTPUT_ID_BUTT] = {
BLE_QIOT_DATA_TYPE_STRING,
};
static ble_action_t sg_ble_action_array[BLE_QIOT_ACTION_ID_BUTT] = {
{ble_action_handle_read_property_input_cb, ble_action_handle_read_property_output_cb,
sg_ble_action_read_property_input_type_array, sg_ble_action_read_property_output_type_array,
sizeof(sg_ble_action_read_property_input_type_array) / sizeof(uint8_t),
sizeof(sg_ble_action_read_property_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)
{
if (action_id >= BLE_QIOT_ACTION_ID_BUTT) {
ble_qiot_log_e("invalid action id %d", action_id);
return -1;
}
int data_len = 0;
if (NULL != sg_ble_action_array[action_id].output_cb) {
data_len = sg_ble_action_array[action_id].output_cb(output_id, buf, buf_len);
if (0 > data_len) {
ble_qiot_log_e("output handle error");
return -1;
}
}
return data_len;
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,301 @@
/*
* 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>
#define BLE_QIOT_SDK_VER "0.1.0"
// data type in template
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
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
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 request type
enum {
BLE_QIOT_EFFECT_REQUEST = 0,
BLE_QIOT_EFFECT_REPLY,
BLE_QIOT_EFFECT_BUTT,
};
// define message type from remote
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 msg type up to remote
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,
};
// 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))
// parse tlv struct
#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))
typedef int (*get_string_cb)(char *buf, uint16_t buf_len, int *offset);
// define property id
enum {
BLE_QIOT_PROPERTY_ID_POWER_SWITCH = 0,
BLE_QIOT_PROPERTY_ID_HEART_RATE,
BLE_QIOT_PROPERTY_ID_BLOOD_OXYGEN,
BLE_QIOT_PROPERTY_ID_BUTT,
};
// define heart_rate attributes
#define BLE_QIOT_PROPERTY_HEART_RATE_MIN (0)
#define BLE_QIOT_PROPERTY_HEART_RATE_MAX (255)
#define BLE_QIOT_PROPERTY_HEART_RATE_START (0)
// define blood_oxygen attributes
#define BLE_QIOT_PROPERTY_BLOOD_OXYGEN_MIN (70)
#define BLE_QIOT_PROPERTY_BLOOD_OXYGEN_MAX (100)
#define BLE_QIOT_PROPERTY_BLOOD_OXYGEN_START (70)
// define property set handle. return 0 if success, other is error
typedef int (*property_set_cb)(const char *data, uint16_t len);
// define property get handle. return the data length obtained, 0 is error
typedef int (*property_get_cb)(char *buf, uint16_t buf_len);
// define property struct
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_SLEEP_REPORT = 0,
BLE_QIOT_EVENT_ID_SLEEP_DATA,
BLE_QIOT_EVENT_ID_HEART_RATE_DATA,
BLE_QIOT_EVENT_ID_BLOOD_OXYGEN_DATA,
BLE_QIOT_EVENT_ID_TODAY_ACTIVITY,
BLE_QIOT_EVENT_ID_BUTT,
};
// define event param sleep_report
enum {
BLE_QIOT_EVENT_SLEEP_REPORT_PARAM_ID_TOTAL_SLEEP_TIME = 0,
BLE_QIOT_EVENT_SLEEP_REPORT_PARAM_ID_FALLING_ASLEEP_TIME,
BLE_QIOT_EVENT_SLEEP_REPORT_PARAM_ID_WAKEUP_TIME,
BLE_QIOT_EVENT_SLEEP_REPORT_PARAM_ID_DEEP_SLEEP_TIME,
BLE_QIOT_EVENT_SLEEP_REPORT_PARAM_ID_LIGHT_SLEEP_TIME,
BLE_QIOT_EVENT_SLEEP_REPORT_PARAM_ID_SLEEP_SCORE,
BLE_QIOT_EVENT_SLEEP_REPORT_PARAM_ID_BUTT,
};
// define total_sleep_time attributes
#define BLE_QIOT_EVENT_SLEEP_REPORT_TOTAL_SLEEP_TIME_MIN (0)
#define BLE_QIOT_EVENT_SLEEP_REPORT_TOTAL_SLEEP_TIME_MAX (86400)
// define deep_sleep_time attributes
#define BLE_QIOT_EVENT_SLEEP_REPORT_DEEP_SLEEP_TIME_MIN (0)
#define BLE_QIOT_EVENT_SLEEP_REPORT_DEEP_SLEEP_TIME_MAX (1440)
// define light_sleep_time attributes
#define BLE_QIOT_EVENT_SLEEP_REPORT_LIGHT_SLEEP_TIME_MIN (0)
#define BLE_QIOT_EVENT_SLEEP_REPORT_LIGHT_SLEEP_TIME_MAX (1440)
// define sleep_score attributes
#define BLE_QIOT_EVENT_SLEEP_REPORT_SLEEP_SCORE_MIN (-1)
#define BLE_QIOT_EVENT_SLEEP_REPORT_SLEEP_SCORE_MAX (100)
// define event param sleep_data
enum {
BLE_QIOT_EVENT_SLEEP_DATA_PARAM_ID_DATA = 0,
BLE_QIOT_EVENT_SLEEP_DATA_PARAM_ID_BUTT,
};
// define data attributes
#define BLE_QIOT_EVENT_SLEEP_DATA_DATA_LEN_MIN (1)
#define BLE_QIOT_EVENT_SLEEP_DATA_DATA_LEN_MAX (2048)
// define event param heart_rate_data
enum {
BLE_QIOT_EVENT_HEART_RATE_DATA_PARAM_ID_DATA = 0,
BLE_QIOT_EVENT_HEART_RATE_DATA_PARAM_ID_BUTT,
};
// define data attributes
#define BLE_QIOT_EVENT_HEART_RATE_DATA_DATA_LEN_MIN (1)
#define BLE_QIOT_EVENT_HEART_RATE_DATA_DATA_LEN_MAX (2048)
// define event param blood_oxygen_data
enum {
BLE_QIOT_EVENT_BLOOD_OXYGEN_DATA_PARAM_ID_DATA = 0,
BLE_QIOT_EVENT_BLOOD_OXYGEN_DATA_PARAM_ID_BUTT,
};
// define data attributes
#define BLE_QIOT_EVENT_BLOOD_OXYGEN_DATA_DATA_LEN_MIN (1)
#define BLE_QIOT_EVENT_BLOOD_OXYGEN_DATA_DATA_LEN_MAX (2048)
// define event param today_activity
enum {
BLE_QIOT_EVENT_TODAY_ACTIVITY_PARAM_ID_DATA = 0,
BLE_QIOT_EVENT_TODAY_ACTIVITY_PARAM_ID_BUTT,
};
// define data attributes
#define BLE_QIOT_EVENT_TODAY_ACTIVITY_DATA_LEN_MIN (1)
#define BLE_QIOT_EVENT_TODAY_ACTIVITY_DATA_LEN_MAX (2048)
// define event get handle. return 0 if success, other is error
typedef int (*event_get_cb)(char *buf, uint16_t buf_len);
// define param struct of event
typedef struct {
event_get_cb get_cb; // get param data callback
uint8_t type; // param type
} ble_event_param;
// define event struct
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_READ_PROPERTY = 0,
BLE_QIOT_ACTION_ID_BUTT,
};
// define action input read_property
enum {
BLE_QIOT_ACTION_READ_PROPERTY_INPUT_ID_ID = 0,
BLE_QIOT_ACTION_READ_PROPERTY_INPUT_ID_BUTT,
};
// define action output read_property
enum {
BLE_QIOT_ACTION_READ_PROPERTY_OUTPUT_ID_VALUE = 0,
BLE_QIOT_ACTION_READ_PROPERTY_OUTPUT_ID_BUTT,
};
#define BLE_QIOT_ACTION_INPUT_READ_PROPERTY_ID_MIN (0)
#define BLE_QIOT_ACTION_INPUT_READ_PROPERTY_ID_MAX (2)
#define BLE_QIOT_ACTION_INPUT_READ_PROPERTY_ID_START (0)
#define BLE_QIOT_ACTION_INPUT_READ_PROPERTY_ID_STEP (1)
// define value attributes
#define BLE_QIOT_ACTION_OUTPUT_READ_PROPERTY_VALUE_MIN (0)
#define BLE_QIOT_ACTION_OUTPUT_READ_PROPERTY_VALUE_MAX (255)
// define max input id and output id
#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. output_id_array filling with id number that need
// obtained
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
typedef int (*action_output_handle)(uint8_t output_id, char *buf, uint16_t buf_len);
// define action id struct
typedef struct {
action_input_handle input_cb; // handle input data
action_output_handle output_cb; // get output data in the callback
uint8_t * input_type_array; // type array for input id
uint8_t * output_type_array; // type array for output id
uint8_t input_id_size; // numbers of input id
uint8_t output_id_size; // numbers of output id
} ble_action_t;
// property module
uint8_t ble_get_property_type_by_id(uint8_t id);
int ble_user_property_set_data(const e_ble_tlv *tlv);
int ble_user_property_get_data_by_id(uint8_t id, char *buf, uint16_t buf_len);
int ble_user_property_report_reply_handle(uint8_t result);
// event module
int ble_event_get_id_array_size(uint8_t event_id);
uint8_t ble_event_get_param_id_type(uint8_t event_id, uint8_t param_id);
int ble_event_get_data_by_id(uint8_t event_id, uint8_t param_id, char *out_buf, uint16_t buf_len);
int ble_user_event_reply_handle(uint8_t event_id, uint8_t result);
// action module
uint8_t ble_action_get_intput_type_by_id(uint8_t action_id, uint8_t input_id);
uint8_t ble_action_get_output_type_by_id(uint8_t action_id, uint8_t output_id);
int ble_action_get_input_id_size(uint8_t action_id);
int ble_action_get_output_id_size(uint8_t action_id);
int ble_action_user_handle_input_param(uint8_t action_id, e_ble_tlv *input_param_array, uint8_t input_array_size,
uint8_t *output_id_array);
int ble_action_user_handle_output_param(uint8_t action_id, uint8_t output_id, char *buf, uint16_t buf_len);
#ifdef __cplusplus
}
#endif
#endif // BLE_QIOT_TEMPLATE_H_

View File

@@ -0,0 +1,237 @@
{
"version": "1.0",
"profile": {
"ProductId": "0BCDALFUO8",
"CategoryId": "141"
},
"properties": [
{
"id": "power_switch",
"name": "手环开关",
"desc": "创建产品必须添加的属性",
"required": true,
"mode": "rw",
"define": {
"type": "bool",
"mapping": {
"0": "关",
"1": "开"
}
}
},
{
"id": "heart_rate",
"name": "心率值",
"desc": "统计用户心率数据",
"required": true,
"mode": "r",
"define": {
"type": "int",
"unit": "bpm",
"step": "",
"min": "0",
"max": "255",
"start": "0"
}
},
{
"id": "blood_oxygen",
"name": "血氧值",
"desc": "统计用户血氧数据",
"required": true,
"mode": "r",
"define": {
"type": "int",
"unit": "%",
"step": "",
"min": "70",
"max": "100",
"start": "70"
}
}
],
"events": [
{
"id": "sleep_report",
"name": "睡眠报告",
"desc": "用户睡眠报告",
"type": "info",
"required": true,
"params": [
{
"id": "total_sleep_time",
"name": "总睡眠时间",
"desc": "用户总睡眠时间记录",
"define": {
"type": "int",
"unit": "秒",
"step": "",
"min": "0",
"max": "86400"
}
},
{
"id": "falling_asleep_time",
"name": "入睡时间",
"desc": "用户入睡时间记录",
"define": {
"type": "timestamp"
}
},
{
"id": "wakeup_time",
"name": "醒来时间",
"desc": "用户醒来时间记录",
"define": {
"type": "timestamp"
}
},
{
"id": "deep_sleep_time",
"name": "深睡时间",
"desc": "用户深度睡眠时间记录",
"define": {
"type": "int",
"unit": "分钟",
"step": "",
"min": "0",
"max": "1440"
}
},
{
"id": "light_sleep_time",
"name": "浅睡时间",
"desc": "用户浅度睡眠时间记录",
"define": {
"type": "int",
"unit": "分钟",
"step": "",
"min": "0",
"max": "1440"
}
},
{
"id": "sleep_score",
"name": "睡眠评分",
"desc": "用户睡眠评分,-1为无评分功能",
"define": {
"type": "int",
"unit": "",
"step": "",
"min": "-1",
"max": "100"
}
}
]
},
{
"id": "sleep_data",
"name": "睡眠数据",
"desc": "用户睡眠数据记录",
"type": "info",
"required": true,
"params": [
{
"id": "data",
"name": "睡眠数据",
"desc": "",
"define": {
"type": "string",
"min": "1",
"max": "2048"
}
}
]
},
{
"id": "heart_rate_data",
"name": "心率数据",
"desc": "用户心率数据记录",
"type": "info",
"required": true,
"params": [
{
"id": "data",
"name": "心率数据",
"desc": "",
"define": {
"type": "string",
"min": "1",
"max": "2048"
}
}
]
},
{
"id": "blood_oxygen_data",
"name": "血氧数据",
"desc": "用户血氧数据记录",
"type": "info",
"required": true,
"params": [
{
"id": "data",
"name": "血氧数据",
"desc": "",
"define": {
"type": "string",
"min": "1",
"max": "2048"
}
}
]
},
{
"id": "today_activity",
"name": "今日活动",
"desc": "用户今日活动数据记录",
"type": "info",
"required": true,
"params": [
{
"id": "data",
"name": "活动数据",
"desc": "",
"define": {
"type": "string",
"min": "1",
"max": "2048"
}
}
]
}
],
"actions": [
{
"id": "read_property",
"name": "属性读取",
"desc": "",
"input": [
{
"id": "id",
"name": "属性ID",
"define": {
"type": "int",
"min": "0",
"max": "2",
"start": "0",
"step": "1",
"unit": ""
}
}
],
"output": [
{
"id": "value",
"name": "属性值",
"define": {
"type": "string",
"min": "1",
"max": "2048"
}
}
],
"required": true
}
]
}

View File

@@ -0,0 +1,55 @@
/*----------------------------------------------------------------------------
* Name: Dbg_RAM.ini
* Purpose: RAM Debug Initialization File
* Note(s):
*----------------------------------------------------------------------------
* This file is part of the uVision/ARM development tools.
* This software may only be used under the terms of a valid, current,
* end user licence from KEIL for a compatible version of KEIL software
* development tools. Nothing else gives you the right to use this software.
*
* This software is supplied "AS IS" without warranties of any kind.
*
* Copyright (c) 2008-2013 Keil - An ARM Company. All rights reserved.
*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------
TraceSetup() Turn on ITM clocks, etc.
*----------------------------------------------------------------------------*/
FUNC void TraceSetup (void)
{
// turn on the ITM/TPIU clock
//_WDWORD(0x40020250, 0x00000201); // TPIU clock enabled at 3MHz
}
/*----------------------------------------------------------------------------
Setup() configure PC & SP for RAM Debug
*----------------------------------------------------------------------------*/
FUNC void Setup (void) {
SP = _RDWORD(0x0000C000+0x0); // Setup Stack Pointer
PC = _RDWORD(0x0000C000+0x4); // Setup Program Counter
_WDWORD(0xE000ED08, 0x0000C000+0x0); // Setup Vector Table Offset Register (done in system file)
}
/*----------------------------------------------------------------------------
OnResetExec() executed after reset via uVision's 'Reset'-button
*----------------------------------------------------------------------------*/
FUNC void OnResetExec (void)
{
}
LOAD %L INCREMENTAL // load the application
Setup(); // Setup for Running
BS main
g
/*----------------------------------------------------------------------------
*----------------------------------------------------------------------------*/

View File

@@ -0,0 +1,40 @@
[BREAKPOINTS]
ForceImpTypeAny = 0
ShowInfoWin = 1
EnableFlashBP = 2
BPDuringExecution = 0
[CFI]
CFISize = 0x00
CFIAddr = 0x00
[CPU]
MonModeVTableAddr = 0xFFFFFFFF
MonModeDebug = 0
MaxNumAPs = 0
LowPowerHandlingMode = 0
OverrideMemMap = 0
AllowSimulation = 1
; ScriptFile="AMAPH1KK-KBR.JLinkScript"
[FLASH]
CacheExcludeSize = 0x00
CacheExcludeAddr = 0x00
MinNumBytesFlashDL = 0
SkipProgOnCRCMatch = 1
VerifyDownload = 1
AllowCaching = 1
EnableFlashDL = 2
Override = 1
Device="AMA3B1KK-KBR"
[GENERAL]
WorkRAMSize = 0x00
WorkRAMAddr = 0x00
RAMUsageLimit = 0x00
[SWO]
SWOLogFile=""
[MEM]
RdOverrideOrMask = 0x00
RdOverrideAndMask = 0xFFFFFFFF
RdOverrideAddr = 0xFFFFFFFF
WrOverrideOrMask = 0x00
WrOverrideAndMask = 0xFFFFFFFF
WrOverrideAddr = 0xFFFFFFFF

View File

@@ -0,0 +1,80 @@
#******************************************************************************
#
# Makefile - Rules for building the libraries, examples and docs.
#
# Copyright (c) 2020, Ambiq Micro
# 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 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 the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from this
# software without specific prior written permission.
#
# Third party software included in this distribution is subject to the
# additional license terms as defined in the /docs/licenses directory.
#
# 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 THE COPYRIGHT HOLDER 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.
#
# This is part of revision 2.4.2 of the AmbiqSuite Development Package.
#
#******************************************************************************
TARGET := ble_freertos_watch
COMPILERNAME := Keil
PROJECT := ble_freertos_watch_Keil
CONFIG := bin
SHELL:=/bin/bash
#### Required Executables ####
K := $(shell type -p UV4.exe)
RM := $(shell which rm 2>/dev/null)
ifeq ($(K),)
all clean:
$(info Tools w/$(COMPILERNAME) not installed.)
$(RM) -rf bin
else
all: directories binary
.PHONY: binary
binary:
UV4.exe -b -t "ble_freertos_watch" ble_freertos_watch.uvprojx -j0 || [ $$? -eq 1 ]
directories: $(CONFIG)
$(CONFIG):
@mkdir -p $@
clean:
@echo Cleaning... ;\
$(RM) -rf $(CONFIG)
../../../bsp/keil/bin/libam_bsp.lib:
$(MAKE) -C ../../../bsp
../../../../../mcu/apollo3/hal/keil/bin/libam_hal.lib:
$(MAKE) -C ../../../../../mcu/apollo3/hal
endif
.PHONY: all clean directories

View File

@@ -0,0 +1,60 @@
;******************************************************************************
;
; ble_freertos_watch.sct
;
; Scatter file for Keil linker configuration.
;
;******************************************************************************
;******************************************************************************
;
; Copyright (c) 2020, Ambiq Micro
; 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 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 the copyright holder nor the names of its
; contributors may be used to endorse or promote products derived from this
; software without specific prior written permission.
;
; Third party software included in this distribution is subject to the
; additional license terms as defined in the /docs/licenses directory.
;
; 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 THE COPYRIGHT HOLDER 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.
;
; This is part of revision 2.4.2 of the AmbiqSuite Development Package.
;
;******************************************************************************
LR_1 0x0000C000
{
FLASH 0x0000C000 0x000F0000
{
*.o (RESET, +First)
* (+RO)
}
SRAM 0x10000000 0x00060000
{
startup_keil.o (STACK, +First)
* (+RW, +ZI)
}
}

View File

@@ -0,0 +1,408 @@
;******************************************************************************
;
;! @file startup_keil.s
;!
;! @brief Definitions for Apollo3 interrupt handlers, the vector table, and the stack.
;
;******************************************************************************
;******************************************************************************
;
; Copyright (c) 2020, Ambiq Micro
; 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 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 the copyright holder nor the names of its
; contributors may be used to endorse or promote products derived from this
; software without specific prior written permission.
;
; Third party software included in this distribution is subject to the
; additional license terms as defined in the /docs/licenses directory.
;
; 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 THE COPYRIGHT HOLDER 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.
;
; This is part of revision 2.4.2 of the AmbiqSuite Development Package.
;
;******************************************************************************
;******************************************************************************
;
; <o> Stack Size (in Bytes) <0x0-0xFFFFFFFF:8>
;************************************************************************
Stack EQU 0x00002B00
;******************************************************************************
;
; <o> Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
;
;******************************************************************************
Heap EQU 0x00000000
;******************************************************************************
;
; Allocate space for the stack.
;
;******************************************************************************
AREA STACK, NOINIT, READWRITE, ALIGN=3
StackMem
SPACE Stack
__initial_sp
;******************************************************************************
;
; Allocate space for the heap.
;
;******************************************************************************
AREA HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base
HeapMem
SPACE Heap
__heap_limit
;******************************************************************************
;
; Indicate that the code in this file preserves 8-byte alignment of the stack.
;
;******************************************************************************
PRESERVE8
;******************************************************************************
;
; Place code into the reset code section.
;
;******************************************************************************
AREA RESET, CODE, READONLY
THUMB
;******************************************************************************
;
; The vector table.
;
;******************************************************************************
;
; Note: Aliasing and weakly exporting am_mpufault_isr, am_busfault_isr, and
; am_usagefault_isr does not work if am_fault_isr is defined externally.
; Therefore, we'll explicitly use am_fault_isr in the table for those vectors.
;
EXPORT __Vectors
__Vectors
DCD StackMem + Stack ; Top of Stack
DCD Reset_Handler ; Reset Handler
DCD NMI_Handler ; NMI Handler
DCD HardFault_Handler ; Hard Fault Handler
DCD MemManage_Handler ; The MPU fault handler
DCD BusFault_Handler ; The bus fault handler
DCD UsageFault_Handler ; The usage fault handler
DCD SecureFault_Handler ; Secure fault handler
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD SVC_Handler ; SVCall handler
DCD DebugMon_Handler ; Debug monitor handler
DCD 0 ; Reserved
DCD PendSV_Handler ; The PendSV handler
DCD SysTick_Handler ; The SysTick handler
;
; Peripheral Interrupts
;
DCD am_brownout_isr ; 0: Reserved
DCD am_watchdog_isr ; 1: Reserved
DCD am_rtc_isr ; 2: RTC
DCD am_vcomp_isr ; 3: Voltage Comparator
DCD am_ioslave_ios_isr ; 4: I/O Slave general
DCD am_ioslave_acc_isr ; 5: I/O Slave access
DCD am_iomaster0_isr ; 6: I/O Master 0
DCD am_iomaster1_isr ; 7: I/O Master 1
DCD am_iomaster2_isr ; 8: I/O Master 2
DCD am_iomaster3_isr ; 9: I/O Master 3
DCD am_iomaster4_isr ; 10: I/O Master 4
DCD am_iomaster5_isr ; 11: I/O Master 5
DCD am_ble_isr ; 12: BLEIF
DCD am_gpio_isr ; 13: GPIO
DCD am_ctimer_isr ; 14: CTIMER
DCD am_uart_isr ; 15: UART0
DCD am_uart1_isr ; 16: UART1
DCD am_scard_isr ; 17: SCARD
DCD am_adc_isr ; 18: ADC
DCD am_pdm0_isr ; 19: PDM
DCD am_mspi0_isr ; 20: MSPI0
DCD am_software0_isr ; 21: SOFTWARE0
DCD am_stimer_isr ; 22: SYSTEM TIMER
DCD am_stimer_cmpr0_isr ; 23: SYSTEM TIMER COMPARE0
DCD am_stimer_cmpr1_isr ; 24: SYSTEM TIMER COMPARE1
DCD am_stimer_cmpr2_isr ; 25: SYSTEM TIMER COMPARE2
DCD am_stimer_cmpr3_isr ; 26: SYSTEM TIMER COMPARE3
DCD am_stimer_cmpr4_isr ; 27: SYSTEM TIMER COMPARE4
DCD am_stimer_cmpr5_isr ; 28: SYSTEM TIMER COMPARE5
DCD am_stimer_cmpr6_isr ; 29: SYSTEM TIMER COMPARE6
DCD am_stimer_cmpr7_isr ; 30: SYSTEM TIMER COMPARE7
DCD am_clkgen_isr ; 31: CLKGEN
__Vectors_End
__Vectors_Size EQU __Vectors_End - __Vectors
;******************************************************************************
;
; Place code immediately following vector table.
;
;******************************************************************************
;******************************************************************************
;
; The Patch table.
;
; The patch table should pad the vector table size to a total of 64 entries
; (16 core + 48 periph) such that code begins at offset 0x100.
;
;******************************************************************************
EXPORT __Patchable
__Patchable
DCD 0 ; 32
DCD 0 ; 33
DCD 0 ; 34
DCD 0 ; 35
DCD 0 ; 36
DCD 0 ; 37
DCD 0 ; 38
DCD 0 ; 39
DCD 0 ; 40
DCD 0 ; 41
DCD 0 ; 42
DCD 0 ; 43
DCD 0 ; 44
DCD 0 ; 45
DCD 0 ; 46
DCD 0 ; 47
;******************************************************************************
;
; This is the code that gets called when the processor first starts execution
; following a reset event.
;
;******************************************************************************
Reset_Handler PROC
EXPORT Reset_Handler [WEAK]
IMPORT __main
;
; Enable the FPU.
;
MOVW R0, #0xED88
MOVT R0, #0xE000
LDR R1, [R0]
ORR R1, #0x00F00000
STR R1, [R0]
DSB
ISB
;
; Branch to main.
;
LDR R0, =__main
BX R0
ENDP
;******************************************************************************
;
; Weak Exception Handlers.
;
;******************************************************************************
HardFault_Handler\
PROC
EXPORT HardFault_Handler [WEAK]
B .
ENDP
NMI_Handler PROC
EXPORT NMI_Handler [WEAK]
B .
ENDP
MemManage_Handler\
PROC
EXPORT MemManage_Handler [WEAK]
B .
ENDP
BusFault_Handler\
PROC
EXPORT BusFault_Handler [WEAK]
B .
ENDP
UsageFault_Handler\
PROC
EXPORT UsageFault_Handler [WEAK]
B .
ENDP
SecureFault_Handler\
PROC
EXPORT SecureFault_Handler [WEAK]
B .
ENDP
SVC_Handler PROC
EXPORT SVC_Handler [WEAK]
B .
ENDP
DebugMon_Handler PROC
EXPORT DebugMon_Handler [WEAK]
B .
ENDP
PendSV_Handler PROC
EXPORT PendSV_Handler [WEAK]
B .
ENDP
SysTick_Handler PROC
EXPORT SysTick_Handler [WEAK]
B .
ENDP
am_default_isr\
PROC
EXPORT am_brownout_isr [WEAK]
EXPORT am_watchdog_isr [WEAK]
EXPORT am_rtc_isr [WEAK]
EXPORT am_vcomp_isr [WEAK]
EXPORT am_ioslave_ios_isr [WEAK]
EXPORT am_ioslave_acc_isr [WEAK]
EXPORT am_iomaster0_isr [WEAK]
EXPORT am_iomaster1_isr [WEAK]
EXPORT am_iomaster2_isr [WEAK]
EXPORT am_iomaster3_isr [WEAK]
EXPORT am_iomaster4_isr [WEAK]
EXPORT am_iomaster5_isr [WEAK]
EXPORT am_ble_isr [WEAK]
EXPORT am_gpio_isr [WEAK]
EXPORT am_ctimer_isr [WEAK]
EXPORT am_uart_isr [WEAK]
EXPORT am_uart0_isr [WEAK]
EXPORT am_uart1_isr [WEAK]
EXPORT am_scard_isr [WEAK]
EXPORT am_adc_isr [WEAK]
EXPORT am_pdm0_isr [WEAK]
EXPORT am_mspi0_isr [WEAK]
EXPORT am_software0_isr [WEAK]
EXPORT am_stimer_isr [WEAK]
EXPORT am_stimer_cmpr0_isr [WEAK]
EXPORT am_stimer_cmpr1_isr [WEAK]
EXPORT am_stimer_cmpr2_isr [WEAK]
EXPORT am_stimer_cmpr3_isr [WEAK]
EXPORT am_stimer_cmpr4_isr [WEAK]
EXPORT am_stimer_cmpr5_isr [WEAK]
EXPORT am_stimer_cmpr6_isr [WEAK]
EXPORT am_stimer_cmpr7_isr [WEAK]
EXPORT am_clkgen_isr [WEAK]
am_brownout_isr
am_watchdog_isr
am_rtc_isr
am_vcomp_isr
am_ioslave_ios_isr
am_ioslave_acc_isr
am_iomaster0_isr
am_iomaster1_isr
am_iomaster2_isr
am_iomaster3_isr
am_iomaster4_isr
am_iomaster5_isr
am_ble_isr
am_gpio_isr
am_ctimer_isr
am_uart_isr
am_uart0_isr
am_uart1_isr
am_scard_isr
am_adc_isr
am_pdm0_isr
am_mspi0_isr
am_software0_isr
am_stimer_isr
am_stimer_cmpr0_isr
am_stimer_cmpr1_isr
am_stimer_cmpr2_isr
am_stimer_cmpr3_isr
am_stimer_cmpr4_isr
am_stimer_cmpr5_isr
am_stimer_cmpr6_isr
am_stimer_cmpr7_isr
am_clkgen_isr
; all device interrupts go here unless the weak label is over
; ridden in the linker hard spin so the debugger will know it
; was an unhandled interrupt request a come-from-buffer or
; instruction trace hardware would sure be nice if you get here
B .
ENDP
;******************************************************************************
;
; Align the end of the section.
;
;******************************************************************************
ALIGN
;******************************************************************************
;
; Initialization of the heap and stack.
;
;******************************************************************************
AREA |.text|, CODE, READONLY
;******************************************************************************
;
; User Initial Stack & Heap.
;
;******************************************************************************
IF :DEF: __MICROLIB
EXPORT __initial_sp
EXPORT __heap_base
EXPORT __heap_limit
ELSE
IMPORT __use_two_region_memory
EXPORT __user_initial_stackheap
__user_initial_stackheap PROC
LDR R0, =HeapMem
LDR R1, =(StackMem + Stack)
LDR R2, =(HeapMem + Heap)
LDR R3, =StackMem
BX LR
ENDP
ENDIF
;******************************************************************************
;
; Align the end of the section.
;
;******************************************************************************
ALIGN
;******************************************************************************
;
; All Done
;
;******************************************************************************
END

View File

@@ -0,0 +1,6 @@
# 说明
1. 本工程基于 Ambiq Micro Apollo 3 Blue 平台开发请联系厂商获取SDK
2. Keil工程的DeviceFamilyPack为 `AmbiqMicro.Apollo_DFP.1.2.0.pack`,请前往 [官网](http://s3.asia.ambiqmicro.com/pack/AmbiqMicro.Apollo_DFP.1.2.0.pack)下载
3. 例程keil工程文件路径 `\qcloud_iot_explorer_ble\samples\lifesense\keil`
4. 5. 使用 code_extract.py 脚本抽取代码得到 `qcloud-iot-ble-lifesense` 目录,请将该目录放置 NORDIC SDK 的 `\boards\apollo3_evb\examples\` 目录下打开keil工程编译即可

View File

@@ -0,0 +1,377 @@
/*********************************************************************
* SEGGER Microcontroller GmbH *
* The Embedded Experts *
**********************************************************************
* *
* (c) 1995 - 2019 SEGGER Microcontroller GmbH *
* *
* 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 *
* condition is met: *
* *
* o Redistributions of source code must retain the above copyright *
* notice, this condition and the following disclaimer. *
* *
* 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.82 *
* *
**********************************************************************
---------------------------END-OF-HEADER------------------------------
File : SEGGER_RTT.h
Purpose : Implementation of SEGGER real-time transfer which allows
real-time communication on targets which support debugger
memory accesses while the CPU is running.
Revision: $Rev: 20159 $
----------------------------------------------------------------------
*/
#ifndef SEGGER_RTT_H
#define SEGGER_RTT_H
#include "SEGGER_RTT_Conf.h"
/*********************************************************************
*
* Defines, defaults
*
**********************************************************************
*/
#ifndef RTT_USE_ASM
#if (defined __SES_ARM) // SEGGER Embedded Studio
#define _CC_HAS_RTT_ASM_SUPPORT 1
#elif (defined __CROSSWORKS_ARM) // Rowley Crossworks
#define _CC_HAS_RTT_ASM_SUPPORT 1
#elif (defined __ARMCC_VERSION)
#define _CC_HAS_RTT_ASM_SUPPORT 0
#elif (defined __GNUC__) // GCC
#define _CC_HAS_RTT_ASM_SUPPORT 1
#elif (defined __clang__) // Clang compiler
#define _CC_HAS_RTT_ASM_SUPPORT 1
#elif ((defined __IASMARM__) || (defined __ICCARM__)) // IAR assembler/compiler
#define _CC_HAS_RTT_ASM_SUPPORT 1
#else
#define _CC_HAS_RTT_ASM_SUPPORT 0
#endif
#if ((defined __IASMARM__) || (defined __ICCARM__)) // IAR assembler/compiler
//
// IAR assembler / compiler
//
#if (defined __ARM7M__) // Needed for old versions that do not know the define yet
#if (__CORE__ == __ARM7M__) // Cortex-M3
#define _CORE_HAS_RTT_ASM_SUPPORT 1
#endif
#endif
#if (defined __ARM7EM__) // Needed for old versions that do not know the define yet
#if (__CORE__ == __ARM7EM__) // Cortex-M4/M7
#define _CORE_HAS_RTT_ASM_SUPPORT 1
#define _CORE_NEEDS_DMB 1
#define RTT__DMB() asm("DMB");
#endif
#endif
#if (defined __ARM8M_BASELINE__) // Needed for old versions that do not know the define yet
#if (__CORE__ == __ARM8M_BASELINE__) // Cortex-M23
#define _CORE_HAS_RTT_ASM_SUPPORT 1
#define _CORE_NEEDS_DMB 1
#define RTT__DMB() asm("DMB");
#endif
#endif
#if (defined __ARM8M_MAINLINE__) // Needed for old versions that do not know the define yet
#if (__CORE__ == __ARM8M_MAINLINE__) // Cortex-M33
#define _CORE_HAS_RTT_ASM_SUPPORT 1
#define _CORE_NEEDS_DMB 1
#define RTT__DMB() asm("DMB");
#endif
#endif
#else
//
// GCC / Clang
//
#if (defined __ARM_ARCH_7M__) // Cortex-M3
#define _CORE_HAS_RTT_ASM_SUPPORT 1
#elif (defined __ARM_ARCH_7EM__) // Cortex-M4/M7
#define _CORE_HAS_RTT_ASM_SUPPORT 1
#define _CORE_NEEDS_DMB 1
#define RTT__DMB() __asm volatile ("dmb\n" : : :);
#elif (defined __ARM_ARCH_8M_BASE__) // Cortex-M23
#define _CORE_HAS_RTT_ASM_SUPPORT 1
#define _CORE_NEEDS_DMB 1
#define RTT__DMB() __asm volatile ("dmb\n" : : :);
#elif (defined __ARM_ARCH_8M_MAIN__) // Cortex-M33
#define _CORE_HAS_RTT_ASM_SUPPORT 1
#define _CORE_NEEDS_DMB 1
#define RTT__DMB() __asm volatile ("dmb\n" : : :);
#else
#define _CORE_HAS_RTT_ASM_SUPPORT 0
#endif
#endif
//
// If IDE and core support the ASM version, enable ASM version by default
//
#ifndef _CORE_HAS_RTT_ASM_SUPPORT
#define _CORE_HAS_RTT_ASM_SUPPORT 0 // Default for unknown cores
#endif
#if (_CC_HAS_RTT_ASM_SUPPORT && _CORE_HAS_RTT_ASM_SUPPORT)
#define RTT_USE_ASM (1)
#else
#define RTT_USE_ASM (0)
#endif
#endif
//
// We need to know if a DMB is needed to make sure that on Cortex-M7 etc.
// the order of accesses to the ring buffers is guaranteed
// Needed for: Cortex-M7, Cortex-M23, Cortex-M33
//
#ifndef _CORE_NEEDS_DMB
#define _CORE_NEEDS_DMB 0
#endif
#ifndef RTT__DMB
#if _CORE_NEEDS_DMB
#error "Don't know how to place inline assembly for DMB"
#else
#define RTT__DMB()
#endif
#endif
#ifndef SEGGER_RTT_ASM // defined when SEGGER_RTT.h is included from assembly file
#include <stdlib.h>
#include <stdarg.h>
/*********************************************************************
*
* Defines, fixed
*
**********************************************************************
*/
/*********************************************************************
*
* Types
*
**********************************************************************
*/
//
// Description for a circular buffer (also called "ring buffer")
// which is used as up-buffer (T->H)
//
typedef struct {
const char* sName; // Optional name. Standard names so far are: "Terminal", "SysView", "J-Scope_t4i4"
char* pBuffer; // Pointer to start of buffer
unsigned SizeOfBuffer; // Buffer size in bytes. Note that one byte is lost, as this implementation does not fill up the buffer in order to avoid the problem of being unable to distinguish between full and empty.
unsigned WrOff; // Position of next item to be written by either target.
volatile unsigned RdOff; // Position of next item to be read by host. Must be volatile since it may be modified by host.
unsigned Flags; // Contains configuration flags
} SEGGER_RTT_BUFFER_UP;
//
// Description for a circular buffer (also called "ring buffer")
// which is used as down-buffer (H->T)
//
typedef struct {
const char* sName; // Optional name. Standard names so far are: "Terminal", "SysView", "J-Scope_t4i4"
char* pBuffer; // Pointer to start of buffer
unsigned SizeOfBuffer; // Buffer size in bytes. Note that one byte is lost, as this implementation does not fill up the buffer in order to avoid the problem of being unable to distinguish between full and empty.
volatile unsigned WrOff; // Position of next item to be written by host. Must be volatile since it may be modified by host.
unsigned RdOff; // Position of next item to be read by target (down-buffer).
unsigned Flags; // Contains configuration flags
} SEGGER_RTT_BUFFER_DOWN;
//
// RTT control block which describes the number of buffers available
// as well as the configuration for each buffer
//
//
typedef struct {
char acID[16]; // Initialized to "SEGGER RTT"
int MaxNumUpBuffers; // Initialized to SEGGER_RTT_MAX_NUM_UP_BUFFERS (type. 2)
int MaxNumDownBuffers; // Initialized to SEGGER_RTT_MAX_NUM_DOWN_BUFFERS (type. 2)
SEGGER_RTT_BUFFER_UP aUp[SEGGER_RTT_MAX_NUM_UP_BUFFERS]; // Up buffers, transferring information up from target via debug probe to host
SEGGER_RTT_BUFFER_DOWN aDown[SEGGER_RTT_MAX_NUM_DOWN_BUFFERS]; // Down buffers, transferring information down from host via debug probe to target
} SEGGER_RTT_CB;
/*********************************************************************
*
* Global data
*
**********************************************************************
*/
extern SEGGER_RTT_CB _SEGGER_RTT;
/*********************************************************************
*
* RTT API functions
*
**********************************************************************
*/
#ifdef __cplusplus
extern "C" {
#endif
int SEGGER_RTT_AllocDownBuffer (const char* sName, void* pBuffer, unsigned BufferSize, unsigned Flags);
int SEGGER_RTT_AllocUpBuffer (const char* sName, void* pBuffer, unsigned BufferSize, unsigned Flags);
int SEGGER_RTT_ConfigUpBuffer (unsigned BufferIndex, const char* sName, void* pBuffer, unsigned BufferSize, unsigned Flags);
int SEGGER_RTT_ConfigDownBuffer (unsigned BufferIndex, const char* sName, void* pBuffer, unsigned BufferSize, unsigned Flags);
int SEGGER_RTT_GetKey (void);
unsigned SEGGER_RTT_HasData (unsigned BufferIndex);
int SEGGER_RTT_HasKey (void);
unsigned SEGGER_RTT_HasDataUp (unsigned BufferIndex);
void SEGGER_RTT_Init (void);
unsigned SEGGER_RTT_Read (unsigned BufferIndex, void* pBuffer, unsigned BufferSize);
unsigned SEGGER_RTT_ReadNoLock (unsigned BufferIndex, void* pData, unsigned BufferSize);
int SEGGER_RTT_SetNameDownBuffer (unsigned BufferIndex, const char* sName);
int SEGGER_RTT_SetNameUpBuffer (unsigned BufferIndex, const char* sName);
int SEGGER_RTT_SetFlagsDownBuffer (unsigned BufferIndex, unsigned Flags);
int SEGGER_RTT_SetFlagsUpBuffer (unsigned BufferIndex, unsigned Flags);
int SEGGER_RTT_WaitKey (void);
unsigned SEGGER_RTT_Write (unsigned BufferIndex, const void* pBuffer, unsigned NumBytes);
unsigned SEGGER_RTT_WriteNoLock (unsigned BufferIndex, const void* pBuffer, unsigned NumBytes);
unsigned SEGGER_RTT_WriteSkipNoLock (unsigned BufferIndex, const void* pBuffer, unsigned NumBytes);
unsigned SEGGER_RTT_ASM_WriteSkipNoLock (unsigned BufferIndex, const void* pBuffer, unsigned NumBytes);
unsigned SEGGER_RTT_WriteString (unsigned BufferIndex, const char* s);
void SEGGER_RTT_WriteWithOverwriteNoLock(unsigned BufferIndex, const void* pBuffer, unsigned NumBytes);
unsigned SEGGER_RTT_PutChar (unsigned BufferIndex, char c);
unsigned SEGGER_RTT_PutCharSkip (unsigned BufferIndex, char c);
unsigned SEGGER_RTT_PutCharSkipNoLock (unsigned BufferIndex, char c);
unsigned SEGGER_RTT_GetAvailWriteSpace (unsigned BufferIndex);
unsigned SEGGER_RTT_GetBytesInBuffer (unsigned BufferIndex);
//
// Function macro for performance optimization
//
#define SEGGER_RTT_HASDATA(n) (_SEGGER_RTT.aDown[n].WrOff - _SEGGER_RTT.aDown[n].RdOff)
#if RTT_USE_ASM
#define SEGGER_RTT_WriteSkipNoLock SEGGER_RTT_ASM_WriteSkipNoLock
#endif
/*********************************************************************
*
* RTT transfer functions to send RTT data via other channels.
*
**********************************************************************
*/
unsigned SEGGER_RTT_ReadUpBuffer (unsigned BufferIndex, void* pBuffer, unsigned BufferSize);
unsigned SEGGER_RTT_ReadUpBufferNoLock (unsigned BufferIndex, void* pData, unsigned BufferSize);
unsigned SEGGER_RTT_WriteDownBuffer (unsigned BufferIndex, const void* pBuffer, unsigned NumBytes);
unsigned SEGGER_RTT_WriteDownBufferNoLock (unsigned BufferIndex, const void* pBuffer, unsigned NumBytes);
#define SEGGER_RTT_HASDATA_UP(n) (_SEGGER_RTT.aUp[n].WrOff - _SEGGER_RTT.aUp[n].RdOff)
/*********************************************************************
*
* RTT "Terminal" API functions
*
**********************************************************************
*/
int SEGGER_RTT_SetTerminal (unsigned char TerminalId);
int SEGGER_RTT_TerminalOut (unsigned char TerminalId, const char* s);
/*********************************************************************
*
* RTT printf functions (require SEGGER_RTT_printf.c)
*
**********************************************************************
*/
int SEGGER_RTT_printf(unsigned BufferIndex, const char * sFormat, ...);
int SEGGER_RTT_vprintf(unsigned BufferIndex, const char * sFormat, va_list * pParamList);
#ifdef __cplusplus
}
#endif
#endif // ifndef(SEGGER_RTT_ASM)
/*********************************************************************
*
* Defines
*
**********************************************************************
*/
//
// Operating modes. Define behavior if buffer is full (not enough space for entire message)
//
#define SEGGER_RTT_MODE_NO_BLOCK_SKIP (0) // Skip. Do not block, output nothing. (Default)
#define SEGGER_RTT_MODE_NO_BLOCK_TRIM (1) // Trim: Do not block, output as much as fits.
#define SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL (2) // Block: Wait until there is space in the buffer.
#define SEGGER_RTT_MODE_MASK (3)
//
// Control sequences, based on ANSI.
// Can be used to control color, and clear the screen
//
#define RTT_CTRL_RESET "\x1B[0m" // Reset to default colors
#define RTT_CTRL_CLEAR "\x1B[2J" // Clear screen, reposition cursor to top left
#define RTT_CTRL_TEXT_BLACK "\x1B[2;30m"
#define RTT_CTRL_TEXT_RED "\x1B[2;31m"
#define RTT_CTRL_TEXT_GREEN "\x1B[2;32m"
#define RTT_CTRL_TEXT_YELLOW "\x1B[2;33m"
#define RTT_CTRL_TEXT_BLUE "\x1B[2;34m"
#define RTT_CTRL_TEXT_MAGENTA "\x1B[2;35m"
#define RTT_CTRL_TEXT_CYAN "\x1B[2;36m"
#define RTT_CTRL_TEXT_WHITE "\x1B[2;37m"
#define RTT_CTRL_TEXT_BRIGHT_BLACK "\x1B[1;30m"
#define RTT_CTRL_TEXT_BRIGHT_RED "\x1B[1;31m"
#define RTT_CTRL_TEXT_BRIGHT_GREEN "\x1B[1;32m"
#define RTT_CTRL_TEXT_BRIGHT_YELLOW "\x1B[1;33m"
#define RTT_CTRL_TEXT_BRIGHT_BLUE "\x1B[1;34m"
#define RTT_CTRL_TEXT_BRIGHT_MAGENTA "\x1B[1;35m"
#define RTT_CTRL_TEXT_BRIGHT_CYAN "\x1B[1;36m"
#define RTT_CTRL_TEXT_BRIGHT_WHITE "\x1B[1;37m"
#define RTT_CTRL_BG_BLACK "\x1B[24;40m"
#define RTT_CTRL_BG_RED "\x1B[24;41m"
#define RTT_CTRL_BG_GREEN "\x1B[24;42m"
#define RTT_CTRL_BG_YELLOW "\x1B[24;43m"
#define RTT_CTRL_BG_BLUE "\x1B[24;44m"
#define RTT_CTRL_BG_MAGENTA "\x1B[24;45m"
#define RTT_CTRL_BG_CYAN "\x1B[24;46m"
#define RTT_CTRL_BG_WHITE "\x1B[24;47m"
#define RTT_CTRL_BG_BRIGHT_BLACK "\x1B[4;40m"
#define RTT_CTRL_BG_BRIGHT_RED "\x1B[4;41m"
#define RTT_CTRL_BG_BRIGHT_GREEN "\x1B[4;42m"
#define RTT_CTRL_BG_BRIGHT_YELLOW "\x1B[4;43m"
#define RTT_CTRL_BG_BRIGHT_BLUE "\x1B[4;44m"
#define RTT_CTRL_BG_BRIGHT_MAGENTA "\x1B[4;45m"
#define RTT_CTRL_BG_BRIGHT_CYAN "\x1B[4;46m"
#define RTT_CTRL_BG_BRIGHT_WHITE "\x1B[4;47m"
#endif
/*************************** End of file ****************************/

View File

@@ -0,0 +1,241 @@
/*********************************************************************
* (c) SEGGER Microcontroller GmbH *
* The Embedded Experts *
* www.segger.com *
**********************************************************************
-------------------------- END-OF-HEADER -----------------------------
File : SEGGER_RTT_ASM_ARMv7M.S
Purpose : Assembler implementation of RTT functions for ARMv7M
Additional information:
This module is written to be assembler-independent and works with
GCC and clang (Embedded Studio) and IAR.
*/
#define SEGGER_RTT_ASM // Used to control processed input from header file
#include "SEGGER_RTT.h"
/*********************************************************************
*
* Defines, fixed
*
**********************************************************************
*/
#define _CCIAR 0
#define _CCCLANG 1
#if (defined __SES_ARM) || (defined __GNUC__) || (defined __clang__)
#define _CC_TYPE _CCCLANG
#define _PUB_SYM .global
#define _EXT_SYM .extern
#define _END .end
#define _WEAK .weak
#define _THUMB_FUNC .thumb_func
#define _THUMB_CODE .code 16
#define _WORD .word
#define _SECTION(Sect, Type, AlignExp) .section Sect ##, "ax"
#define _ALIGN(Exp) .align Exp
#define _PLACE_LITS .ltorg
#define _DATA_SECT_START
#define _C_STARTUP _start
#define _STACK_END __stack_end__
#define _RAMFUNC
//
// .text => Link to flash
// .fast => Link to RAM
// OtherSect => Usually link to RAM
// Alignment is 2^x
//
#elif defined (__IASMARM__)
#define _CC_TYPE _CCIAR
#define _PUB_SYM PUBLIC
#define _EXT_SYM EXTERN
#define _END END
#define _WEAK _WEAK
#define _THUMB_FUNC
#define _THUMB_CODE THUMB
#define _WORD DCD
#define _SECTION(Sect, Type, AlignExp) SECTION Sect ## : ## Type ## :REORDER:NOROOT ## (AlignExp)
#define _ALIGN(Exp) alignrom Exp
#define _PLACE_LITS
#define _DATA_SECT_START DATA
#define _C_STARTUP __iar_program_start
#define _STACK_END sfe(CSTACK)
#define _RAMFUNC SECTION_TYPE SHT_PROGBITS, SHF_WRITE | SHF_EXECINSTR
//
// .text => Link to flash
// .textrw => Link to RAM
// OtherSect => Usually link to RAM
// NOROOT => Allows linker to throw away the function, if not referenced
// Alignment is 2^x
//
#endif
#if (_CC_TYPE == _CCIAR)
NAME SEGGER_RTT_ASM_ARMv7M
#else
.syntax unified
#endif
#if defined (RTT_USE_ASM) && (RTT_USE_ASM == 1)
#define SHT_PROGBITS 0x1
/*********************************************************************
*
* Public / external symbols
*
**********************************************************************
*/
_EXT_SYM __aeabi_memcpy
_EXT_SYM __aeabi_memcpy4
_EXT_SYM _SEGGER_RTT
_PUB_SYM SEGGER_RTT_ASM_WriteSkipNoLock
/*********************************************************************
*
* SEGGER_RTT_WriteSkipNoLock
*
* Function description
* Stores a specified number of characters in SEGGER RTT
* control block which is then read by the host.
* SEGGER_RTT_WriteSkipNoLock does not lock the application and
* skips all data, if the data does not fit into the buffer.
*
* Parameters
* BufferIndex Index of "Up"-buffer to be used (e.g. 0 for "Terminal").
* pBuffer Pointer to character array. Does not need to point to a \0 terminated string.
* NumBytes Number of bytes to be stored in the SEGGER RTT control block.
* MUST be > 0!!!
* This is done for performance reasons, so no initial check has do be done.
*
* Return value
* 1: Data has been copied
* 0: No space, data has not been copied
*
* Notes
* (1) If there is not enough space in the "Up"-buffer, all data is dropped.
* (2) For performance reasons this function does not call Init()
* and may only be called after RTT has been initialized.
* Either by calling SEGGER_RTT_Init() or calling another RTT API function first.
*/
_SECTION(.text, CODE, 2)
_ALIGN(2)
_THUMB_FUNC
SEGGER_RTT_ASM_WriteSkipNoLock: // unsigned SEGGER_RTT_WriteSkipNoLock(unsigned BufferIndex, const void* pData, unsigned NumBytes) {
//
// Cases:
// 1) RdOff <= WrOff => Space until wrap-around is sufficient
// 2) RdOff <= WrOff => Space after wrap-around needed (copy in 2 chunks)
// 3) RdOff < WrOff => No space in buf
// 4) RdOff > WrOff => Space is sufficient
// 5) RdOff > WrOff => No space in buf
//
// 1) is the most common case for large buffers and assuming that J-Link reads the data fast enough
//
// Register usage:
// R0 Temporary needed as RdOff, <Tmp> register later on
// R1 pData
// R2 <NumBytes>
// R3 <Tmp> register. Hold free for subroutine calls
// R4 <Rem>
// R5 pRing->pBuffer
// R6 pRing (Points to active struct SEGGER_RTT_BUFFER_DOWN)
// R7 WrOff
//
PUSH {R4-R7}
ADD R3,R0,R0, LSL #+1
LDR.W R0,=_SEGGER_RTT // pRing = &_SEGGER_RTT.aUp[BufferIndex];
ADD R0,R0,R3, LSL #+3
ADD R6,R0,#+24
LDR R0,[R6, #+16] // RdOff = pRing->RdOff;
LDR R7,[R6, #+12] // WrOff = pRing->WrOff;
LDR R5,[R6, #+4] // pRing->pBuffer
CMP R7,R0
BCC.N _CheckCase4 // if (RdOff <= WrOff) { => Case 1), 2) or 3)
//
// Handling for case 1, later on identical to case 4
//
LDR R3,[R6, #+8] // Avail = pRing->SizeOfBuffer - WrOff - 1u; => Space until wrap-around (assume 1 byte not usable for case that RdOff == 0)
SUBS R4,R3,R7 // <Rem> (Used in case we jump into case 2 afterwards)
SUBS R3,R4,#+1 // <Avail>
CMP R3,R2
BCC.N _CheckCase2 // if (Avail >= NumBytes) { => Case 1)?
_Case4:
ADDS R5,R7,R5 // pBuffer += WrOff
ADDS R0,R2,R7 // v = WrOff + NumBytes
//
// 2x unrolling for the copy loop that is used most of the time
// This is a special optimization for small SystemView packets and makes them even faster
//
_ALIGN(2)
_LoopCopyStraight: // memcpy(pRing->pBuffer + WrOff, pData, NumBytes);
LDRB R3,[R1], #+1
STRB R3,[R5], #+1 // *pDest++ = *pSrc++
SUBS R2,R2,#+1
BEQ _CSDone
LDRB R3,[R1], #+1
STRB R3,[R5], #+1 // *pDest++ = *pSrc++
SUBS R2,R2,#+1
BNE _LoopCopyStraight
_CSDone:
#if _CORE_NEEDS_DMB // Do not slow down cores that do not need a DMB instruction here
DMB // Cortex-M7 may delay memory writes and also change the order in which the writes happen. Therefore, make sure that all buffer writes are finished, before updating the <WrOff> in the struct
#endif
STR R0,[R6, #+12] // pRing->WrOff = WrOff + NumBytes;
MOVS R0,#+1
POP {R4-R7}
BX LR // Return 1
_CheckCase2:
ADDS R0,R0,R3 // Avail += RdOff; => Space incl. wrap-around
CMP R0,R2
BCC.N _Case3 // if (Avail >= NumBytes) { => Case 2? => If not, we have case 3) (does not fit)
//
// Handling for case 2
//
ADDS R0,R7,R5 // v = pRing->pBuffer + WrOff => Do not change pRing->pBuffer here because 2nd chunk needs org. value
SUBS R2,R2,R4 // NumBytes -= Rem; (Rem = pRing->SizeOfBuffer - WrOff; => Space until end of buffer)
_LoopCopyBeforeWrapAround: // memcpy(pRing->pBuffer + WrOff, pData, Rem); => Copy 1st chunk
LDRB R3,[R1], #+1
STRB R3,[R0], #+1 // *pDest++ = *pSrc++
SUBS R4,R4,#+1
BNE _LoopCopyBeforeWrapAround
//
// Special case: First check that assumed RdOff == 0 calculated that last element before wrap-around could not be used
// But 2nd check (considering space until wrap-around and until RdOff) revealed that RdOff is not 0, so we can use the last element
// In this case, we may use a copy straight until buffer end anyway without needing to copy 2 chunks
// Therefore, check if 2nd memcpy is necessary at all
//
ADDS R4,R2,#+0 // Save <NumBytes> (needed as counter in loop but must be written to <WrOff> after the loop). Also use this inst to update the flags to skip 2nd loop if possible
BEQ.N _No2ChunkNeeded // if (NumBytes) {
_LoopCopyAfterWrapAround: // memcpy(pRing->pBuffer, pData + Rem, NumBytes);
LDRB R3,[R1], #+1 // pData already points to the next src byte due to copy loop increment before this loop
STRB R3,[R5], #+1 // *pDest++ = *pSrc++
SUBS R2,R2,#+1
BNE _LoopCopyAfterWrapAround
_No2ChunkNeeded:
#if _CORE_NEEDS_DMB // Do not slow down cores that do not need a DMB instruction here
DMB // Cortex-M7 may delay memory writes and also change the order in which the writes happen. Therefore, make sure that all buffer writes are finished, before updating the <WrOff> in the struct
#endif
STR R4,[R6, #+12] // pRing->WrOff = NumBytes; => Must be written after copying data because J-Link may read control block asynchronously while writing into buffer
MOVS R0,#+1
POP {R4-R7}
BX LR // Return 1
_CheckCase4:
SUBS R0,R0,R7
SUBS R0,R0,#+1 // Avail = RdOff - WrOff - 1u;
CMP R0,R2
BCS.N _Case4 // if (Avail >= NumBytes) { => Case 4) == 1) ? => If not, we have case 5) == 3) (does not fit)
_Case3:
MOVS R0,#+0
POP {R4-R7}
BX LR // Return 0
_PLACE_LITS
#endif // defined (RTT_USE_ASM) && (RTT_USE_ASM == 1)
_END
/*************************** End of file ****************************/

View File

@@ -0,0 +1,389 @@
/*********************************************************************
* SEGGER Microcontroller GmbH *
* The Embedded Experts *
**********************************************************************
* *
* (c) 1995 - 2019 SEGGER Microcontroller GmbH *
* *
* 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 *
* condition is met: *
* *
* o Redistributions of source code must retain the above copyright *
* notice, this condition and the following disclaimer. *
* *
* 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.82 *
* *
**********************************************************************
---------------------------END-OF-HEADER------------------------------
File : SEGGER_RTT_Conf.h
Purpose : Implementation of SEGGER real-time transfer (RTT) which
allows real-time communication on targets which support
debugger memory accesses while the CPU is running.
Revision: $Rev: 18601 $
*/
#ifndef SEGGER_RTT_CONF_H
#define SEGGER_RTT_CONF_H
#ifdef __IAR_SYSTEMS_ICC__
#include <intrinsics.h>
#endif
/*********************************************************************
*
* Defines, configurable
*
**********************************************************************
*/
#ifndef SEGGER_RTT_MAX_NUM_UP_BUFFERS
#define SEGGER_RTT_MAX_NUM_UP_BUFFERS (3) // Max. number of up-buffers (T->H) available on this target (Default: 3)
#endif
#ifndef SEGGER_RTT_MAX_NUM_DOWN_BUFFERS
#define SEGGER_RTT_MAX_NUM_DOWN_BUFFERS (3) // Max. number of down-buffers (H->T) available on this target (Default: 3)
#endif
#ifndef BUFFER_SIZE_UP
#define BUFFER_SIZE_UP (1024) // Size of the buffer for terminal output of target, up to host (Default: 1k)
#endif
#ifndef BUFFER_SIZE_DOWN
#define BUFFER_SIZE_DOWN (16) // Size of the buffer for terminal input to target from host (Usually keyboard input) (Default: 16)
#endif
#ifndef SEGGER_RTT_PRINTF_BUFFER_SIZE
#define SEGGER_RTT_PRINTF_BUFFER_SIZE (64u) // Size of buffer for RTT printf to bulk-send chars via RTT (Default: 64)
#endif
#ifndef SEGGER_RTT_MODE_DEFAULT
#define SEGGER_RTT_MODE_DEFAULT SEGGER_RTT_MODE_NO_BLOCK_SKIP // Mode for pre-initialized terminal channel (buffer 0)
#endif
/*********************************************************************
*
* RTT memcpy configuration
*
* memcpy() is good for large amounts of data,
* but the overhead is big for small amounts, which are usually stored via RTT.
* With SEGGER_RTT_MEMCPY_USE_BYTELOOP a simple byte loop can be used instead.
*
* SEGGER_RTT_MEMCPY() can be used to replace standard memcpy() in RTT functions.
* This is may be required with memory access restrictions,
* such as on Cortex-A devices with MMU.
*/
#ifndef SEGGER_RTT_MEMCPY_USE_BYTELOOP
#define SEGGER_RTT_MEMCPY_USE_BYTELOOP 0 // 0: Use memcpy/SEGGER_RTT_MEMCPY, 1: Use a simple byte-loop
#endif
//
// Example definition of SEGGER_RTT_MEMCPY to external memcpy with GCC toolchains and Cortex-A targets
//
//#if ((defined __SES_ARM) || (defined __CROSSWORKS_ARM) || (defined __GNUC__)) && (defined (__ARM_ARCH_7A__))
// #define SEGGER_RTT_MEMCPY(pDest, pSrc, NumBytes) SEGGER_memcpy((pDest), (pSrc), (NumBytes))
//#endif
//
// Target is not allowed to perform other RTT operations while string still has not been stored completely.
// Otherwise we would probably end up with a mixed string in the buffer.
// If using RTT from within interrupts, multiple tasks or multi processors, define the SEGGER_RTT_LOCK() and SEGGER_RTT_UNLOCK() function here.
//
// SEGGER_RTT_MAX_INTERRUPT_PRIORITY can be used in the sample lock routines on Cortex-M3/4.
// Make sure to mask all interrupts which can send RTT data, i.e. generate SystemView events, or cause task switches.
// When high-priority interrupts must not be masked while sending RTT data, SEGGER_RTT_MAX_INTERRUPT_PRIORITY needs to be adjusted accordingly.
// (Higher priority = lower priority number)
// Default value for embOS: 128u
// Default configuration in FreeRTOS: configMAX_SYSCALL_INTERRUPT_PRIORITY: ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
// In case of doubt mask all interrupts: 1 << (8 - BASEPRI_PRIO_BITS) i.e. 1 << 5 when 3 bits are implemented in NVIC
// or define SEGGER_RTT_LOCK() to completely disable interrupts.
//
#ifndef SEGGER_RTT_MAX_INTERRUPT_PRIORITY
#define SEGGER_RTT_MAX_INTERRUPT_PRIORITY (0x20) // Interrupt priority to lock on SEGGER_RTT_LOCK on Cortex-M3/4 (Default: 0x20)
#endif
/*********************************************************************
*
* RTT lock configuration for SEGGER Embedded Studio,
* Rowley CrossStudio and GCC
*/
#if ((defined(__SES_ARM) || defined(__SES_RISCV) || defined(__CROSSWORKS_ARM) || defined(__GNUC__) || defined(__clang__)) && !defined (__CC_ARM) && !defined(WIN32))
#if (defined(__ARM_ARCH_6M__) || defined(__ARM_ARCH_8M_BASE__))
#define SEGGER_RTT_LOCK() { \
unsigned int LockState; \
__asm volatile ("mrs %0, primask \n\t" \
"movs r1, $1 \n\t" \
"msr primask, r1 \n\t" \
: "=r" (LockState) \
: \
: "r1" \
);
#define SEGGER_RTT_UNLOCK() __asm volatile ("msr primask, %0 \n\t" \
: \
: "r" (LockState) \
: \
); \
}
#elif (defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) || defined(__ARM_ARCH_8M_MAIN__))
#ifndef SEGGER_RTT_MAX_INTERRUPT_PRIORITY
#define SEGGER_RTT_MAX_INTERRUPT_PRIORITY (0x20)
#endif
#define SEGGER_RTT_LOCK() { \
unsigned int LockState; \
__asm volatile ("mrs %0, basepri \n\t" \
"mov r1, %1 \n\t" \
"msr basepri, r1 \n\t" \
: "=r" (LockState) \
: "i"(SEGGER_RTT_MAX_INTERRUPT_PRIORITY) \
: "r1" \
);
#define SEGGER_RTT_UNLOCK() __asm volatile ("msr basepri, %0 \n\t" \
: \
: "r" (LockState) \
: \
); \
}
#elif defined(__ARM_ARCH_7A__)
#define SEGGER_RTT_LOCK() { \
unsigned int LockState; \
__asm volatile ("mrs r1, CPSR \n\t" \
"mov %0, r1 \n\t" \
"orr r1, r1, #0xC0 \n\t" \
"msr CPSR_c, r1 \n\t" \
: "=r" (LockState) \
: \
: "r1" \
);
#define SEGGER_RTT_UNLOCK() __asm volatile ("mov r0, %0 \n\t" \
"mrs r1, CPSR \n\t" \
"bic r1, r1, #0xC0 \n\t" \
"and r0, r0, #0xC0 \n\t" \
"orr r1, r1, r0 \n\t" \
"msr CPSR_c, r1 \n\t" \
: \
: "r" (LockState) \
: "r0", "r1" \
); \
}
#elif defined(__riscv) || defined(__riscv_xlen)
#define SEGGER_RTT_LOCK() { \
unsigned int LockState; \
__asm volatile ("csrr %0, mstatus \n\t" \
"csrci mstatus, 8 \n\t" \
"andi %0, %0, 8 \n\t" \
: "=r" (LockState) \
: \
: \
);
#define SEGGER_RTT_UNLOCK() __asm volatile ("csrr a1, mstatus \n\t" \
"or %0, %0, a1 \n\t" \
"csrs mstatus, %0 \n\t" \
: \
: "r" (LockState) \
: "a1" \
); \
}
#else
#define SEGGER_RTT_LOCK()
#define SEGGER_RTT_UNLOCK()
#endif
#endif
/*********************************************************************
*
* RTT lock configuration for IAR EWARM
*/
#ifdef __ICCARM__
#if (defined (__ARM6M__) && (__CORE__ == __ARM6M__)) || \
(defined (__ARM8M_BASELINE__) && (__CORE__ == __ARM8M_BASELINE__))
#define SEGGER_RTT_LOCK() { \
unsigned int LockState; \
LockState = __get_PRIMASK(); \
__set_PRIMASK(1);
#define SEGGER_RTT_UNLOCK() __set_PRIMASK(LockState); \
}
#elif (defined (__ARM7EM__) && (__CORE__ == __ARM7EM__)) || \
(defined (__ARM7M__) && (__CORE__ == __ARM7M__)) || \
(defined (__ARM8M_MAINLINE__) && (__CORE__ == __ARM8M_MAINLINE__)) || \
(defined (__ARM8M_MAINLINE__) && (__CORE__ == __ARM8M_MAINLINE__))
#ifndef SEGGER_RTT_MAX_INTERRUPT_PRIORITY
#define SEGGER_RTT_MAX_INTERRUPT_PRIORITY (0x20)
#endif
#define SEGGER_RTT_LOCK() { \
unsigned int LockState; \
LockState = __get_BASEPRI(); \
__set_BASEPRI(SEGGER_RTT_MAX_INTERRUPT_PRIORITY);
#define SEGGER_RTT_UNLOCK() __set_BASEPRI(LockState); \
}
#endif
#endif
/*********************************************************************
*
* RTT lock configuration for IAR RX
*/
#ifdef __ICCRX__
#define SEGGER_RTT_LOCK() { \
unsigned long LockState; \
LockState = __get_interrupt_state(); \
__disable_interrupt();
#define SEGGER_RTT_UNLOCK() __set_interrupt_state(LockState); \
}
#endif
/*********************************************************************
*
* RTT lock configuration for IAR RL78
*/
#ifdef __ICCRL78__
#define SEGGER_RTT_LOCK() { \
__istate_t LockState; \
LockState = __get_interrupt_state(); \
__disable_interrupt();
#define SEGGER_RTT_UNLOCK() __set_interrupt_state(LockState); \
}
#endif
/*********************************************************************
*
* RTT lock configuration for KEIL ARM
*/
#ifdef __CC_ARM
#if (defined __TARGET_ARCH_6S_M)
#define SEGGER_RTT_LOCK() { \
unsigned int LockState; \
register unsigned char PRIMASK __asm( "primask"); \
LockState = PRIMASK; \
PRIMASK = 1u; \
__schedule_barrier();
#define SEGGER_RTT_UNLOCK() PRIMASK = LockState; \
__schedule_barrier(); \
}
#elif (defined(__TARGET_ARCH_7_M) || defined(__TARGET_ARCH_7E_M))
#ifndef SEGGER_RTT_MAX_INTERRUPT_PRIORITY
#define SEGGER_RTT_MAX_INTERRUPT_PRIORITY (0x20)
#endif
#define SEGGER_RTT_LOCK() { \
unsigned int LockState; \
register unsigned char BASEPRI __asm( "basepri"); \
LockState = BASEPRI; \
BASEPRI = SEGGER_RTT_MAX_INTERRUPT_PRIORITY; \
__schedule_barrier();
#define SEGGER_RTT_UNLOCK() BASEPRI = LockState; \
__schedule_barrier(); \
}
#endif
#endif
/*********************************************************************
*
* RTT lock configuration for TI ARM
*/
#ifdef __TI_ARM__
#if defined (__TI_ARM_V6M0__)
#define SEGGER_RTT_LOCK() { \
unsigned int LockState; \
LockState = __get_PRIMASK(); \
__set_PRIMASK(1);
#define SEGGER_RTT_UNLOCK() __set_PRIMASK(LockState); \
}
#elif (defined (__TI_ARM_V7M3__) || defined (__TI_ARM_V7M4__))
#ifndef SEGGER_RTT_MAX_INTERRUPT_PRIORITY
#define SEGGER_RTT_MAX_INTERRUPT_PRIORITY (0x20)
#endif
#define SEGGER_RTT_LOCK() { \
unsigned int LockState; \
LockState = _set_interrupt_priority(SEGGER_RTT_MAX_INTERRUPT_PRIORITY);
#define SEGGER_RTT_UNLOCK() _set_interrupt_priority(LockState); \
}
#endif
#endif
/*********************************************************************
*
* RTT lock configuration for CCRX
*/
#ifdef __RX
#define SEGGER_RTT_LOCK() { \
unsigned long LockState; \
LockState = get_psw() & 0x010000; \
clrpsw_i();
#define SEGGER_RTT_UNLOCK() set_psw(get_psw() | LockState); \
}
#endif
/*********************************************************************
*
* RTT lock configuration for embOS Simulation on Windows
* (Can also be used for generic RTT locking with embOS)
*/
#if defined(WIN32) || defined(SEGGER_RTT_LOCK_EMBOS)
void OS_SIM_EnterCriticalSection(void);
void OS_SIM_LeaveCriticalSection(void);
#define SEGGER_RTT_LOCK() { \
OS_SIM_EnterCriticalSection();
#define SEGGER_RTT_UNLOCK() OS_SIM_LeaveCriticalSection(); \
}
#endif
/*********************************************************************
*
* RTT lock configuration fallback
*/
#ifndef SEGGER_RTT_LOCK
#define SEGGER_RTT_LOCK() // Lock RTT (nestable) (i.e. disable interrupts)
#endif
#ifndef SEGGER_RTT_UNLOCK
#define SEGGER_RTT_UNLOCK() // Unlock RTT (nestable) (i.e. enable previous interrupt lock state)
#endif
#endif
/*************************** End of file ****************************/

View File

@@ -0,0 +1,125 @@
/*********************************************************************
* SEGGER Microcontroller GmbH *
* The Embedded Experts *
**********************************************************************
* *
* (c) 1995 - 2019 SEGGER Microcontroller GmbH *
* *
* 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 *
* condition is met: *
* *
* o Redistributions of source code must retain the above copyright *
* notice, this condition and the following disclaimer. *
* *
* 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.82 *
* *
**********************************************************************
---------------------------END-OF-HEADER------------------------------
File : SEGGER_RTT_Syscalls_GCC.c
Purpose : Low-level functions for using printf() via RTT in GCC.
To use RTT for printf output, include this file in your
application.
Revision: $Rev: 20159 $
----------------------------------------------------------------------
*/
#if (defined __GNUC__) && !(defined __SES_ARM) && !(defined __CROSSWORKS_ARM) && !(defined __ARMCC_VERSION) && !(defined __CC_ARM)
#include <reent.h> // required for _write_r
#include "SEGGER_RTT.h"
/*********************************************************************
*
* Types
*
**********************************************************************
*/
//
// If necessary define the _reent struct
// to match the one passed by the used standard library.
//
struct _reent;
/*********************************************************************
*
* Function prototypes
*
**********************************************************************
*/
int _write(int file, char *ptr, int len);
int _write_r(struct _reent *r, int file, const void *ptr, int len);
/*********************************************************************
*
* Global functions
*
**********************************************************************
*/
/*********************************************************************
*
* _write()
*
* Function description
* Low-level write function.
* libc subroutines will use this system routine for output to all files,
* including stdout.
* Write data via RTT.
*/
int _write(int file, char *ptr, int len) {
(void) file; /* Not used, avoid warning */
SEGGER_RTT_Write(0, ptr, len);
return len;
}
/*********************************************************************
*
* _write_r()
*
* Function description
* Low-level reentrant write function.
* libc subroutines will use this system routine for output to all files,
* including stdout.
* Write data via RTT.
*/
int _write_r(struct _reent *r, int file, const void *ptr, int len) {
(void) file; /* Not used, avoid warning */
(void) r; /* Not used, avoid warning */
SEGGER_RTT_Write(0, ptr, len);
return len;
}
#endif
/****** End Of File *************************************************/

View File

@@ -0,0 +1,120 @@
/*********************************************************************
* SEGGER Microcontroller GmbH *
* The Embedded Experts *
**********************************************************************
* *
* (c) 1995 - 2019 SEGGER Microcontroller GmbH *
* *
* 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 *
* condition is met: *
* *
* o Redistributions of source code must retain the above copyright *
* notice, this condition and the following disclaimer. *
* *
* 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.82 *
* *
**********************************************************************
---------------------------END-OF-HEADER------------------------------
File : SEGGER_RTT_Syscalls_IAR.c
Purpose : Low-level functions for using printf() via RTT in IAR.
To use RTT for printf output, include this file in your
application and set the Library Configuration to Normal.
Revision: $Rev: 17697 $
----------------------------------------------------------------------
*/
#ifdef __IAR_SYSTEMS_ICC__
//
// Since IAR EWARM V8 and EWRX V4, yfuns.h is considered as deprecated and LowLevelIOInterface.h
// shall be used instead. To not break any compatibility with older compiler versions, we have a
// version check in here.
//
#if ((defined __ICCARM__) && (__VER__ >= 8000000)) || ((defined __ICCRX__) && (__VER__ >= 400))
#include <LowLevelIOInterface.h>
#else
#include <yfuns.h>
#endif
#include "SEGGER_RTT.h"
#pragma module_name = "?__write"
/*********************************************************************
*
* Function prototypes
*
**********************************************************************
*/
size_t __write(int handle, const unsigned char * buffer, size_t size);
/*********************************************************************
*
* Global functions
*
**********************************************************************
*/
/*********************************************************************
*
* __write()
*
* Function description
* Low-level write function.
* Standard library subroutines will use this system routine
* for output to all files, including stdout.
* Write data via RTT.
*/
size_t __write(int handle, const unsigned char * buffer, size_t size) {
(void) handle; /* Not used, avoid warning */
SEGGER_RTT_Write(0, (const char*)buffer, size);
return size;
}
/*********************************************************************
*
* __write_buffered()
*
* Function description
* Low-level write function.
* Standard library subroutines will use this system routine
* for output to all files, including stdout.
* Write data via RTT.
*/
size_t __write_buffered(int handle, const unsigned char * buffer, size_t size) {
(void) handle; /* Not used, avoid warning */
SEGGER_RTT_Write(0, (const char*)buffer, size);
return size;
}
#endif
/****** End Of File *************************************************/

View File

@@ -0,0 +1,393 @@
/*********************************************************************
* SEGGER Microcontroller GmbH *
* The Embedded Experts *
**********************************************************************
* *
* (c) 1995 - 2019 SEGGER Microcontroller GmbH *
* *
* 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 *
* condition is met: *
* *
* o Redistributions of source code must retain the above copyright *
* notice, this condition and the following disclaimer. *
* *
* 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.82 *
* *
**********************************************************************
---------------------------END-OF-HEADER------------------------------
File : RTT_Syscalls_KEIL.c
Purpose : Retargeting module for KEIL MDK-CM3.
Low-level functions for using printf() via RTT
Revision: $Rev: 20159 $
----------------------------------------------------------------------
*/
#if (defined __CC_ARM) || (defined __ARMCC_VERSION)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <rt_sys.h>
#include <rt_misc.h>
#include "SEGGER_RTT.h"
/*********************************************************************
*
* #pragmas
*
**********************************************************************
*/
#if __ARMCC_VERSION < 6000000
#pragma import(__use_no_semihosting)
#endif
#ifdef _MICROLIB
#pragma import(__use_full_stdio)
#endif
/*********************************************************************
*
* Defines non-configurable
*
**********************************************************************
*/
/* Standard IO device handles - arbitrary, but any real file system handles must be
less than 0x8000. */
#define STDIN 0x8001 // Standard Input Stream
#define STDOUT 0x8002 // Standard Output Stream
#define STDERR 0x8003 // Standard Error Stream
/*********************************************************************
*
* Public const
*
**********************************************************************
*/
#if __ARMCC_VERSION < 5000000
//const char __stdin_name[] = "STDIN";
const char __stdout_name[] = "STDOUT";
const char __stderr_name[] = "STDERR";
#endif
/*********************************************************************
*
* Public code
*
**********************************************************************
*/
/*********************************************************************
*
* _ttywrch
*
* Function description:
* Outputs a character to the console
*
* Parameters:
* c - character to output
*
*/
void _ttywrch(int c) {
fputc(c, stdout); // stdout
fflush(stdout);
}
/*********************************************************************
*
* _sys_open
*
* Function description:
* Opens the device/file in order to do read/write operations
*
* Parameters:
* sName - sName of the device/file to open
* OpenMode - This parameter is currently ignored
*
* Return value:
* != 0 - Handle to the object to open, otherwise
* == 0 -"device" is not handled by this module
*
*/
FILEHANDLE _sys_open(const char * sName, int OpenMode) {
(void)OpenMode;
// Register standard Input Output devices.
if (strcmp(sName, __stdout_name) == 0) {
return (STDOUT);
} else if (strcmp(sName, __stderr_name) == 0) {
return (STDERR);
} else
return (0); // Not implemented
}
/*********************************************************************
*
* _sys_close
*
* Function description:
* Closes the handle to the open device/file
*
* Parameters:
* hFile - Handle to a file opened via _sys_open
*
* Return value:
* 0 - device/file closed
*
*/
int _sys_close(FILEHANDLE hFile) {
(void)hFile;
return 0; // Not implemented
}
/*********************************************************************
*
* _sys_write
*
* Function description:
* Writes the data to an open handle.
* Currently this function only outputs data to the console
*
* Parameters:
* hFile - Handle to a file opened via _sys_open
* pBuffer - Pointer to the data that shall be written
* NumBytes - Number of bytes to write
* Mode - The Mode that shall be used
*
* Return value:
* Number of bytes *not* written to the file/device
*
*/
int _sys_write(FILEHANDLE hFile, const unsigned char * pBuffer, unsigned NumBytes, int Mode) {
int r = 0;
(void)Mode;
if (hFile == STDOUT) {
SEGGER_RTT_Write(0, (const char*)pBuffer, NumBytes);
return 0;
}
return r;
}
/*********************************************************************
*
* _sys_read
*
* Function description:
* Reads data from an open handle.
* Currently this modules does nothing.
*
* Parameters:
* hFile - Handle to a file opened via _sys_open
* pBuffer - Pointer to buffer to store the read data
* NumBytes - Number of bytes to read
* Mode - The Mode that shall be used
*
* Return value:
* Number of bytes read from the file/device
*
*/
int _sys_read(FILEHANDLE hFile, unsigned char * pBuffer, unsigned NumBytes, int Mode) {
(void)hFile;
(void)pBuffer;
(void)NumBytes;
(void)Mode;
return (0); // Not implemented
}
/*********************************************************************
*
* _sys_istty
*
* Function description:
* This function shall return whether the opened file
* is a console device or not.
*
* Parameters:
* hFile - Handle to a file opened via _sys_open
*
* Return value:
* 1 - Device is a console
* 0 - Device is not a console
*
*/
int _sys_istty(FILEHANDLE hFile) {
if (hFile > 0x8000) {
return (1);
}
return (0); // Not implemented
}
/*********************************************************************
*
* _sys_seek
*
* Function description:
* Seeks via the file to a specific position
*
* Parameters:
* hFile - Handle to a file opened via _sys_open
* Pos -
*
* Return value:
* int -
*
*/
int _sys_seek(FILEHANDLE hFile, long Pos) {
(void)hFile;
(void)Pos;
return (0); // Not implemented
}
/*********************************************************************
*
* _sys_ensure
*
* Function description:
*
*
* Parameters:
* hFile - Handle to a file opened via _sys_open
*
* Return value:
* int -
*
*/
int _sys_ensure(FILEHANDLE hFile) {
(void)hFile;
return (-1); // Not implemented
}
/*********************************************************************
*
* _sys_flen
*
* Function description:
* Returns the length of the opened file handle
*
* Parameters:
* hFile - Handle to a file opened via _sys_open
*
* Return value:
* Length of the file
*
*/
long _sys_flen(FILEHANDLE hFile) {
(void)hFile;
return (0); // Not implemented
}
/*********************************************************************
*
* _sys_tmpnam
*
* Function description:
* This function converts the file number fileno for a temporary
* file to a unique filename, for example, tmp0001.
*
* Parameters:
* pBuffer - Pointer to a buffer to store the name
* FileNum - file number to convert
* MaxLen - Size of the buffer
*
* Return value:
* 1 - Error
* 0 - Success
*
*/
int _sys_tmpnam(char * pBuffer, int FileNum, unsigned MaxLen) {
(void)pBuffer;
(void)FileNum;
(void)MaxLen;
return (1); // Not implemented
}
/*********************************************************************
*
* _sys_command_string
*
* Function description:
* This function shall execute a system command.
*
* Parameters:
* cmd - Pointer to the command string
* len - Length of the string
*
* Return value:
* == NULL - Command was not successfully executed
* == sCmd - Command was passed successfully
*
*/
char * _sys_command_string(char * cmd, int len) {
(void)len;
return cmd; // Not implemented
}
/*********************************************************************
*
* _sys_exit
*
* Function description:
* This function is called when the application returns from main
*
* Parameters:
* ReturnCode - Return code from the main function
*
*
*/
void _sys_exit(int ReturnCode) {
(void)ReturnCode;
while (1); // Not implemented
}
#if __ARMCC_VERSION >= 5000000
/*********************************************************************
*
* stdout_putchar
*
* Function description:
* Put a character to the stdout
*
* Parameters:
* ch - Character to output
*
*
*/
int stdout_putchar(int ch) {
(void)ch;
return ch; // Not implemented
}
#endif
#endif
/*************************** End of file ****************************/

View File

@@ -0,0 +1,252 @@
/*********************************************************************
* SEGGER Microcontroller GmbH *
* The Embedded Experts *
**********************************************************************
* *
* (c) 1995 - 2019 SEGGER Microcontroller GmbH *
* *
* 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 *
* condition is met: *
* *
* o Redistributions of source code must retain the above copyright *
* notice, this condition and the following disclaimer. *
* *
* 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.82 *
* *
**********************************************************************
---------------------------END-OF-HEADER------------------------------
File : SEGGER_RTT_Syscalls_SES.c
Purpose : Reimplementation of printf, puts and __getchar using RTT
in SEGGER Embedded Studio.
To use RTT for printf output, include this file in your
application.
Revision: $Rev: 18539 $
----------------------------------------------------------------------
*/
#if (defined __SES_ARM) || (defined __SES_RISCV) || (defined __CROSSWORKS_ARM)
#include "SEGGER_RTT.h"
#include <stdarg.h>
#include <stdio.h>
#include "limits.h"
#include "__libc.h"
#include "__vfprintf.h"
/*********************************************************************
*
* Defines, configurable
*
**********************************************************************
*/
//
// Select string formatting implementation.
//
// RTT printf formatting
// - Configurable stack usage. (SEGGER_RTT_PRINTF_BUFFER_SIZE in SEGGER_RTT_Conf.h)
// - No maximum string length.
// - Limited conversion specifiers and flags. (See SEGGER_RTT_printf.c)
// Standard library printf formatting
// - Configurable formatting capabilities.
// - Full conversion specifier and flag support.
// - Maximum string length has to be known or (slightly) slower character-wise output.
//
// #define PRINTF_USE_SEGGER_RTT_FORMATTING 0 // Use standard library formatting
// #define PRINTF_USE_SEGGER_RTT_FORMATTING 1 // Use RTT formatting
//
#ifndef PRINTF_USE_SEGGER_RTT_FORMATTING
#define PRINTF_USE_SEGGER_RTT_FORMATTING 0
#endif
//
// If using standard library formatting,
// select maximum output string buffer size or character-wise output.
//
// #define PRINTF_BUFFER_SIZE 0 // Use character-wise output
// #define PRINTF_BUFFER_SIZE 128 // Default maximum string length
//
#ifndef PRINTF_BUFFER_SIZE
#define PRINTF_BUFFER_SIZE 128
#endif
#if PRINTF_USE_SEGGER_RTT_FORMATTING // Use SEGGER RTT formatting implementation
/*********************************************************************
*
* Function prototypes
*
**********************************************************************
*/
int SEGGER_RTT_vprintf(unsigned BufferIndex, const char * sFormat, va_list * pParamList);
/*********************************************************************
*
* Global functions, printf
*
**********************************************************************
*/
/*********************************************************************
*
* printf()
*
* Function description
* print a formatted string using RTT and SEGGER RTT formatting.
*/
int printf(const char *fmt,...) {
int n;
va_list args;
va_start (args, fmt);
n = SEGGER_RTT_vprintf(0, fmt, &args);
va_end(args);
return n;
}
#elif PRINTF_BUFFER_SIZE == 0 // Use standard library formatting with character-wise output
/*********************************************************************
*
* Static functions
*
**********************************************************************
*/
static int _putchar(int x, __printf_tag_ptr ctx) {
(void)ctx;
SEGGER_RTT_Write(0, (char *)&x, 1);
return x;
}
/*********************************************************************
*
* Global functions, printf
*
**********************************************************************
*/
/*********************************************************************
*
* printf()
*
* Function description
* print a formatted string character-wise, using RTT and standard
* library formatting.
*/
int printf(const char *fmt, ...) {
int n;
va_list args;
__printf_t iod;
va_start(args, fmt);
iod.string = 0;
iod.maxchars = INT_MAX;
iod.output_fn = _putchar;
SEGGER_RTT_LOCK();
n = __vfprintf(&iod, fmt, args);
SEGGER_RTT_UNLOCK();
va_end(args);
return n;
}
#else // Use standard library formatting with static buffer
/*********************************************************************
*
* Global functions, printf
*
**********************************************************************
*/
/*********************************************************************
*
* printf()
*
* Function description
* print a formatted string using RTT and standard library formatting.
*/
int printf(const char *fmt,...) {
int n;
char aBuffer[PRINTF_BUFFER_SIZE];
va_list args;
va_start (args, fmt);
n = vsnprintf(aBuffer, sizeof(aBuffer), fmt, args);
if (n > (int)sizeof(aBuffer)) {
SEGGER_RTT_Write(0, aBuffer, sizeof(aBuffer));
} else if (n > 0) {
SEGGER_RTT_Write(0, aBuffer, n);
}
va_end(args);
return n;
}
#endif
/*********************************************************************
*
* Global functions
*
**********************************************************************
*/
/*********************************************************************
*
* puts()
*
* Function description
* print a string using RTT.
*/
int puts(const char *s) {
return SEGGER_RTT_WriteString(0, s);
}
/*********************************************************************
*
* __putchar()
*
* Function description
* Write one character via RTT.
*/
int __putchar(int x, __printf_tag_ptr ctx) {
(void)ctx;
SEGGER_RTT_Write(0, (char *)&x, 1);
return x;
}
/*********************************************************************
*
* __getchar()
*
* Function description
* Wait for and get a character via RTT.
*/
int __getchar() {
return SEGGER_RTT_WaitKey();
}
#endif
/****** End Of File *************************************************/

View File

@@ -0,0 +1,505 @@
/*********************************************************************
* SEGGER Microcontroller GmbH *
* The Embedded Experts *
**********************************************************************
* *
* (c) 1995 - 2019 SEGGER Microcontroller GmbH *
* *
* 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 *
* condition is met: *
* *
* o Redistributions of source code must retain the above copyright *
* notice, this condition and the following disclaimer. *
* *
* 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.82 *
* *
**********************************************************************
---------------------------END-OF-HEADER------------------------------
File : SEGGER_RTT_printf.c
Purpose : Replacement for printf to write formatted data via RTT
Revision: $Rev: 17697 $
----------------------------------------------------------------------
*/
#include "SEGGER_RTT.h"
#include "SEGGER_RTT_Conf.h"
/*********************************************************************
*
* Defines, configurable
*
**********************************************************************
*/
#ifndef SEGGER_RTT_PRINTF_BUFFER_SIZE
#define SEGGER_RTT_PRINTF_BUFFER_SIZE (64)
#endif
#include <stdlib.h>
#include <stdarg.h>
#define FORMAT_FLAG_LEFT_JUSTIFY (1u << 0)
#define FORMAT_FLAG_PAD_ZERO (1u << 1)
#define FORMAT_FLAG_PRINT_SIGN (1u << 2)
#define FORMAT_FLAG_ALTERNATE (1u << 3)
/*********************************************************************
*
* Types
*
**********************************************************************
*/
typedef struct {
char* pBuffer;
unsigned BufferSize;
unsigned Cnt;
int ReturnValue;
unsigned RTTBufferIndex;
} SEGGER_RTT_PRINTF_DESC;
/*********************************************************************
*
* Function prototypes
*
**********************************************************************
*/
/*********************************************************************
*
* Static code
*
**********************************************************************
*/
/*********************************************************************
*
* _StoreChar
*/
static void _StoreChar(SEGGER_RTT_PRINTF_DESC * p, char c) {
unsigned Cnt;
Cnt = p->Cnt;
if ((Cnt + 1u) <= p->BufferSize) {
*(p->pBuffer + Cnt) = c;
p->Cnt = Cnt + 1u;
p->ReturnValue++;
}
//
// Write part of string, when the buffer is full
//
if (p->Cnt == p->BufferSize) {
if (SEGGER_RTT_Write(p->RTTBufferIndex, p->pBuffer, p->Cnt) != p->Cnt) {
p->ReturnValue = -1;
} else {
p->Cnt = 0u;
}
}
}
/*********************************************************************
*
* _PrintUnsigned
*/
static void _PrintUnsigned(SEGGER_RTT_PRINTF_DESC * pBufferDesc, unsigned v, unsigned Base, unsigned NumDigits, unsigned FieldWidth, unsigned FormatFlags) {
static const char _aV2C[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
unsigned Div;
unsigned Digit;
unsigned Number;
unsigned Width;
char c;
Number = v;
Digit = 1u;
//
// Get actual field width
//
Width = 1u;
while (Number >= Base) {
Number = (Number / Base);
Width++;
}
if (NumDigits > Width) {
Width = NumDigits;
}
//
// Print leading chars if necessary
//
if ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == 0u) {
if (FieldWidth != 0u) {
if (((FormatFlags & FORMAT_FLAG_PAD_ZERO) == FORMAT_FLAG_PAD_ZERO) && (NumDigits == 0u)) {
c = '0';
} else {
c = ' ';
}
while ((FieldWidth != 0u) && (Width < FieldWidth)) {
FieldWidth--;
_StoreChar(pBufferDesc, c);
if (pBufferDesc->ReturnValue < 0) {
break;
}
}
}
}
if (pBufferDesc->ReturnValue >= 0) {
//
// 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) {
if (NumDigits > 1u) { // 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)
NumDigits--;
} else {
Div = v / Digit;
if (Div < Base) { // Is our divider big enough to extract the highest digit from value? => Done
break;
}
}
Digit *= Base;
}
//
// Output digits
//
do {
Div = v / Digit;
v -= Div * Digit;
_StoreChar(pBufferDesc, _aV2C[Div]);
if (pBufferDesc->ReturnValue < 0) {
break;
}
Digit /= Base;
} while (Digit);
//
// Print trailing spaces if necessary
//
if ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == FORMAT_FLAG_LEFT_JUSTIFY) {
if (FieldWidth != 0u) {
while ((FieldWidth != 0u) && (Width < FieldWidth)) {
FieldWidth--;
_StoreChar(pBufferDesc, ' ');
if (pBufferDesc->ReturnValue < 0) {
break;
}
}
}
}
}
}
/*********************************************************************
*
* _PrintInt
*/
static void _PrintInt(SEGGER_RTT_PRINTF_DESC * pBufferDesc, int v, unsigned Base, unsigned NumDigits, unsigned FieldWidth, unsigned FormatFlags) {
unsigned Width;
int Number;
Number = (v < 0) ? -v : v;
//
// Get actual field width
//
Width = 1u;
while (Number >= (int)Base) {
Number = (Number / (int)Base);
Width++;
}
if (NumDigits > Width) {
Width = NumDigits;
}
if ((FieldWidth > 0u) && ((v < 0) || ((FormatFlags & FORMAT_FLAG_PRINT_SIGN) == FORMAT_FLAG_PRINT_SIGN))) {
FieldWidth--;
}
//
// Print leading spaces if necessary
//
if ((((FormatFlags & FORMAT_FLAG_PAD_ZERO) == 0u) || (NumDigits != 0u)) && ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == 0u)) {
if (FieldWidth != 0u) {
while ((FieldWidth != 0u) && (Width < FieldWidth)) {
FieldWidth--;
_StoreChar(pBufferDesc, ' ');
if (pBufferDesc->ReturnValue < 0) {
break;
}
}
}
}
//
// Print sign if necessary
//
if (pBufferDesc->ReturnValue >= 0) {
if (v < 0) {
v = -v;
_StoreChar(pBufferDesc, '-');
} else if ((FormatFlags & FORMAT_FLAG_PRINT_SIGN) == FORMAT_FLAG_PRINT_SIGN) {
_StoreChar(pBufferDesc, '+');
} else {
}
if (pBufferDesc->ReturnValue >= 0) {
//
// Print leading zeros if necessary
//
if (((FormatFlags & FORMAT_FLAG_PAD_ZERO) == FORMAT_FLAG_PAD_ZERO) && ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == 0u) && (NumDigits == 0u)) {
if (FieldWidth != 0u) {
while ((FieldWidth != 0u) && (Width < FieldWidth)) {
FieldWidth--;
_StoreChar(pBufferDesc, '0');
if (pBufferDesc->ReturnValue < 0) {
break;
}
}
}
}
if (pBufferDesc->ReturnValue >= 0) {
//
// Print number without sign
//
_PrintUnsigned(pBufferDesc, (unsigned)v, Base, NumDigits, FieldWidth, FormatFlags);
}
}
}
}
/*********************************************************************
*
* Public code
*
**********************************************************************
*/
/*********************************************************************
*
* SEGGER_RTT_vprintf
*
* Function description
* Stores a formatted string in SEGGER RTT control block.
* This data is read by the host.
*
* Parameters
* BufferIndex Index of "Up"-buffer to be used. (e.g. 0 for "Terminal")
* sFormat Pointer to format string
* pParamList Pointer to the list of arguments for the format string
*
* Return values
* >= 0: Number of bytes which have been stored in the "Up"-buffer.
* < 0: Error
*/
int SEGGER_RTT_vprintf(unsigned BufferIndex, const char * sFormat, va_list * pParamList) {
char c;
SEGGER_RTT_PRINTF_DESC BufferDesc;
int v;
unsigned NumDigits;
unsigned FormatFlags;
unsigned FieldWidth;
char acBuffer[SEGGER_RTT_PRINTF_BUFFER_SIZE];
BufferDesc.pBuffer = acBuffer;
BufferDesc.BufferSize = SEGGER_RTT_PRINTF_BUFFER_SIZE;
BufferDesc.Cnt = 0u;
BufferDesc.RTTBufferIndex = BufferIndex;
BufferDesc.ReturnValue = 0;
do {
c = *sFormat;
sFormat++;
if (c == 0u) {
break;
}
if (c == '%') {
//
// Filter out flags
//
FormatFlags = 0u;
v = 1;
do {
c = *sFormat;
switch (c) {
case '-': FormatFlags |= FORMAT_FLAG_LEFT_JUSTIFY; sFormat++; break;
case '0': FormatFlags |= FORMAT_FLAG_PAD_ZERO; sFormat++; break;
case '+': FormatFlags |= FORMAT_FLAG_PRINT_SIGN; sFormat++; break;
case '#': FormatFlags |= FORMAT_FLAG_ALTERNATE; sFormat++; break;
default: v = 0; break;
}
} while (v);
//
// filter out field with
//
FieldWidth = 0u;
do {
c = *sFormat;
if ((c < '0') || (c > '9')) {
break;
}
sFormat++;
FieldWidth = (FieldWidth * 10u) + ((unsigned)c - '0');
} while (1);
//
// Filter out precision (number of digits to display)
//
NumDigits = 0u;
c = *sFormat;
if (c == '.') {
sFormat++;
do {
c = *sFormat;
if ((c < '0') || (c > '9')) {
break;
}
sFormat++;
NumDigits = NumDigits * 10u + ((unsigned)c - '0');
} while (1);
}
//
// Filter out length modifier
//
c = *sFormat;
do {
if ((c == 'l') || (c == 'h')) {
sFormat++;
c = *sFormat;
} else {
break;
}
} while (1);
//
// Handle specifiers
//
switch (c) {
case 'c': {
char c0;
v = va_arg(*pParamList, int);
c0 = (char)v;
_StoreChar(&BufferDesc, c0);
break;
}
case 'd':
v = va_arg(*pParamList, int);
_PrintInt(&BufferDesc, v, 10u, NumDigits, FieldWidth, FormatFlags);
break;
case 'u':
v = va_arg(*pParamList, int);
_PrintUnsigned(&BufferDesc, (unsigned)v, 10u, NumDigits, FieldWidth, FormatFlags);
break;
case 'x':
case 'X':
v = va_arg(*pParamList, int);
_PrintUnsigned(&BufferDesc, (unsigned)v, 16u, NumDigits, FieldWidth, FormatFlags);
break;
case 's':
{
const char * s = va_arg(*pParamList, const char *);
do {
c = *s;
s++;
if (c == '\0') {
break;
}
_StoreChar(&BufferDesc, c);
} while (BufferDesc.ReturnValue >= 0);
}
break;
case 'p':
v = va_arg(*pParamList, int);
_PrintUnsigned(&BufferDesc, (unsigned)v, 16u, 8u, 8u, 0u);
break;
case '%':
_StoreChar(&BufferDesc, '%');
break;
default:
break;
}
sFormat++;
} else {
_StoreChar(&BufferDesc, c);
}
} while (BufferDesc.ReturnValue >= 0);
if (BufferDesc.ReturnValue > 0) {
//
// Write remaining data, if any
//
if (BufferDesc.Cnt != 0u) {
SEGGER_RTT_Write(BufferIndex, acBuffer, BufferDesc.Cnt);
}
BufferDesc.ReturnValue += (int)BufferDesc.Cnt;
}
return BufferDesc.ReturnValue;
}
/*********************************************************************
*
* SEGGER_RTT_printf
*
* Function description
* Stores a formatted string in SEGGER RTT control block.
* This data is read by the host.
*
* Parameters
* BufferIndex Index of "Up"-buffer to be used. (e.g. 0 for "Terminal")
* sFormat Pointer to format string, followed by the arguments for conversion
*
* Return values
* >= 0: Number of bytes which have been stored in the "Up"-buffer.
* < 0: Error
*
* Notes
* (1) Conversion specifications have following syntax:
* %[flags][FieldWidth][.Precision]ConversionSpecifier
* (2) Supported flags:
* -: Left justify within the field width
* +: Always print sign extension for signed conversions
* 0: Pad with 0 instead of spaces. Ignored when using '-'-flag or precision
* Supported conversion specifiers:
* c: Print the argument as one char
* d: Print the argument as a signed integer
* u: Print the argument as an unsigned integer
* x: Print the argument as an hexadecimal integer
* s: Print the string pointed to by the argument
* p: Print the argument as an 8-digit hexadecimal integer. (Argument shall be a pointer to void.)
*/
int SEGGER_RTT_printf(unsigned BufferIndex, const char * sFormat, ...) {
int r;
va_list ParamList;
va_start(ParamList, sFormat);
r = SEGGER_RTT_vprintf(BufferIndex, sFormat, &ParamList);
va_end(ParamList);
return r;
}
/*************************** End of file ****************************/

View File

@@ -0,0 +1,161 @@
//*****************************************************************************
//
//! @file FreeRTOSConfig.h
//!
//! @brief Configuration options for FreeRTOS
//
//*****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// 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 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 the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// 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 THE COPYRIGHT HOLDER 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.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H
#ifdef __cplusplus
extern "C"
{
#endif
#define configUSE_PREEMPTION 1
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
#ifdef AM_PART_APOLLO2
#define configCPU_CLOCK_HZ 48000000UL
#else
#define configCPU_CLOCK_HZ 24000000UL
#endif
#define configTICK_RATE_HZ 1000
#define configMAX_PRIORITIES 4
#define configMINIMAL_STACK_SIZE (256)
#define configTOTAL_HEAP_SIZE (16 * 1024)
#define configMAX_TASK_NAME_LEN 16
#define configUSE_16_BIT_TICKS 0
#define configIDLE_SHOULD_YIELD 1
#define configUSE_MUTEXES 0
#define configUSE_RECURSIVE_MUTEXES 0
#define configUSE_COUNTING_SEMAPHORES 0
#define configUSE_ALTERNATIVE_API 0 /* Deprecated! */
#define configQUEUE_REGISTRY_SIZE 0
#define configUSE_QUEUE_SETS 0
#define configUSE_TIME_SLICING 0
#define configUSE_NEWLIB_REENTRANT 0
#define configENABLE_BACKWARD_COMPATIBILITY 0
/* Hook function related definitions. */
#define configUSE_IDLE_HOOK 0
#define configUSE_TICK_HOOK 0
#define configCHECK_FOR_STACK_OVERFLOW 2
#define configUSE_MALLOC_FAILED_HOOK 1
/* Run time and task stats gathering related definitions. */
#define configGENERATE_RUN_TIME_STATS 0
#define configUSE_TRACE_FACILITY 0
#define configUSE_STATS_FORMATTING_FUNCTIONS 0
/* Software timer related definitions. */
#define configUSE_TIMERS 1
#define configTIMER_TASK_PRIORITY 3
#define configTIMER_QUEUE_LENGTH 5
#define configTIMER_TASK_STACK_DEPTH configMINIMAL_STACK_SIZE
/* Interrupt nesting behaviour configuration. */
#define configKERNEL_INTERRUPT_PRIORITY (0x7 << 5)
#define configMAX_SYSCALL_INTERRUPT_PRIORITY (0x4 << 5)
#define NVIC_configKERNEL_INTERRUPT_PRIORITY (0x7)
#define NVIC_configMAX_SYSCALL_INTERRUPT_PRIORITY (0x4)
/* Define to trap errors during development. */
#define configASSERT(x) if (( x ) == 0) while(1);
/* FreeRTOS MPU specific definitions. */
#define configINCLUDE_APPLICATION_DEFINED_PRIVILEGED_FUNCTIONS 0
/* Optional functions - most linkers will remove unused functions anyway. */
#define INCLUDE_vTaskPrioritySet 0
#define INCLUDE_uxTaskPriorityGet 0
#define INCLUDE_vTaskDelete 0
#define INCLUDE_vTaskSuspend 1
#define INCLUDE_xResumeFromISR 0
#define INCLUDE_vTaskDelayUntil 1
#define INCLUDE_vTaskDelay 0
#define INCLUDE_xTaskGetSchedulerState 0
#define INCLUDE_xTaskGetCurrentTaskHandle 0
#define INCLUDE_uxTaskGetStackHighWaterMark 0
#define INCLUDE_xTaskGetIdleTaskHandle 0
#define INCLUDE_xTimerGetTimerDaemonTaskHandle 0
#define INCLUDE_pcTaskGetTaskName 0
#define INCLUDE_eTaskGetState 0
#define INCLUDE_xEventGroupSetBitFromISR 1
#define INCLUDE_xTimerPendFunctionCall 1
#define vPortSVCHandler SVC_Handler
#define xPortPendSVHandler PendSV_Handler
#define xPortSysTickHandler SysTick_Handler
#define configOVERRIDE_DEFAULT_TICK_CONFIGURATION 1 // Enable non-SysTick based Tick
#define configUSE_TICKLESS_IDLE 2 // Ambiq specific implementation for Tickless
#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__))
extern uint32_t am_freertos_sleep(uint32_t);
extern void am_freertos_wakeup(uint32_t);
#define configPRE_SLEEP_PROCESSING( time ) \
do { \
(time) = am_freertos_sleep(time); \
} while (0);
#define configPOST_SLEEP_PROCESSING(time) am_freertos_wakeup(time)
#endif
/*-----------------------------------------------------------*/
#ifndef AM_PART_APOLLO
#define AM_FREERTOS_USE_STIMER_FOR_TICK
#endif
#ifdef AM_FREERTOS_USE_STIMER_FOR_TICK
#define configSTIMER_CLOCK_HZ 32768
#else // Use CTimer
#define configCTIMER_CLOCK_HZ 32768
#endif
#ifdef __cplusplus
}
#endif
#endif // FREERTOS_CONFIG_H

View File

@@ -0,0 +1,373 @@
/*
* 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 "apollo3_service.h"
#include <stdint.h>
#include <string.h>
#include "SEGGER_RTT.h"
#include "wsf_types.h"
#include "att_api.h"
#include "app_api.h"
#include "watch_api.h"
#include "ble_qiot_service.h"
#include "ble_qiot_import.h"
#include "ble_qiot_config.h"
// divece configs
#define PRODUCT_ID "LR5NRSX9F5"
#define DEVICE_NAME "ble01"
#define SECRET_KEY "uG2TRl0hnCNsuLgls/65Bg=="
#define ADV_DEVICE_NAME "life_sense"
#define ATTRIBUTE_VALUE_MAX_LEN 256
#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)
uint8_t iot_service_uuid[] = {IOT_BLE_UUID128_SERVICE};
uint16_t iot_service_uuid_len = sizeof(iot_service_uuid);
uint8_t service_uuid[] = {UINT16_TO_BYTES(IOT_BLE_UUID_SERVICE)};
// qiot device info characteristic and attribute
// uint8_t device_info_rx_char[] = {(ATT_PROP_READ | ATT_PROP_WRITE_NO_RSP | ATT_PROP_WRITE), UINT16_TO_BYTES(QIOT_DEVICE_INFO_HDL), IOT_BLE_UUID128_DEVICE_INFO};
uint8_t device_info_rx_char[] = {(ATT_PROP_WRITE_NO_RSP), UINT16_TO_BYTES(QIOT_DEVICE_INFO_HDL), IOT_BLE_UUID128_DEVICE_INFO};
uint16_t device_info_rx_char_len = sizeof(device_info_rx_char);
uint8_t device_info_uuid[] = {IOT_BLE_UUID128_DEVICE_INFO};
uint8_t device_info_attr_value[ATTRIBUTE_VALUE_MAX_LEN] = {0};
uint16_t device_info_attr_value_len = sizeof(device_info_attr_value);
// qiot data characteristic and attribute
// uint8_t data_rx_char[] = {(ATT_PROP_READ | ATT_PROP_WRITE_NO_RSP | ATT_PROP_WRITE), UINT16_TO_BYTES(QIOT_DATA_HDL), IOT_BLE_UUID128_DATA};
uint8_t data_rx_char[] = {(ATT_PROP_WRITE_NO_RSP), UINT16_TO_BYTES(QIOT_DATA_HDL), IOT_BLE_UUID128_DATA};
uint16_t data_rx_char_len = sizeof(data_rx_char);
uint8_t data_uuid[] = {IOT_BLE_UUID128_DATA};
uint8_t data_attr_value[ATTRIBUTE_VALUE_MAX_LEN] = {0};
uint16_t data_attr_value_len = sizeof(data_attr_value);
// qiot event characteristic and attribute
// uint8_t event_rx_char[] = {(ATT_PROP_READ | ATT_PROP_INDICATE | ATT_PROP_NOTIFY), UINT16_TO_BYTES(QIOT_EVENT_HDL), IOT_BLE_UUID128_EVENT};
// uint8_t event_rx_char[] = {(ATT_PROP_INDICATE), UINT16_TO_BYTES(QIOT_EVENT_HDL), IOT_BLE_UUID128_EVENT};
uint8_t event_rx_char[] = {(ATT_PROP_NOTIFY), UINT16_TO_BYTES(QIOT_EVENT_HDL), IOT_BLE_UUID128_EVENT};
uint16_t event_rx_char_len = sizeof(event_rx_char);
uint8_t event_uuid[] = {IOT_BLE_UUID128_EVENT};
uint8_t event_attr_value[ATTRIBUTE_VALUE_MAX_LEN] = {0};
uint16_t event_attr_value_len = sizeof(event_attr_value);
uint8_t event_cccd[] = {0x00, 0x00};
uint16_t event_cccd_len = sizeof(event_cccd);
/* Attribute list for AMDTP group */
static const attsAttr_t qiot_attr_list[] =
{
{
attPrimSvcUuid,
iot_service_uuid,
&iot_service_uuid_len,
sizeof(iot_service_uuid),
0,
ATTS_PERMIT_READ,
},
// qiot device info characteristic and attribute
{
attChUuid,
device_info_rx_char,
&device_info_rx_char_len,
sizeof(device_info_rx_char),
0,
ATTS_PERMIT_READ
},
{
device_info_uuid,
device_info_attr_value,
&device_info_attr_value_len,
sizeof(device_info_attr_value),
(ATTS_SET_UUID_128 | ATTS_SET_VARIABLE_LEN | ATTS_SET_WRITE_CBACK),
// (ATTS_PERMIT_READ | ATTS_PERMIT_WRITE),
ATTS_PERMIT_WRITE,
},
// qiot data characteristic and attribute
{
attChUuid,
data_rx_char,
&data_rx_char_len,
sizeof(data_rx_char),
0,
ATTS_PERMIT_READ
},
{
data_uuid,
data_attr_value,
&data_attr_value_len,
sizeof(data_attr_value),
(ATTS_SET_UUID_128 | ATTS_SET_VARIABLE_LEN | ATTS_SET_WRITE_CBACK),
// (ATTS_PERMIT_READ | ATTS_PERMIT_WRITE),
ATTS_PERMIT_WRITE,
},
// qiot event characteristic and attribute
{
attChUuid,
event_rx_char,
&event_rx_char_len,
sizeof(event_rx_char),
0,
ATTS_PERMIT_READ
},
{
event_uuid,
event_attr_value,
&event_attr_value_len,
sizeof(event_attr_value),
// (ATTS_SET_UUID_128 | ATTS_SET_VARIABLE_LEN | ATTS_SET_WRITE_CBACK),
// (ATTS_PERMIT_READ | ATTS_PERMIT_WRITE),
0,
0,
},
{
attCliChCfgUuid,
(uint8_t *) event_cccd,
(uint16_t *) &event_cccd_len,
sizeof(event_cccd),
ATTS_SET_CCC,
(ATTS_PERMIT_READ | ATTS_PERMIT_WRITE)
},
};
static attsGroup_t qiot_attr_group =
{
NULL,
(attsAttr_t *) &qiot_attr_list,
NULL,
NULL,
QIOT_START_HDL,
QIOT_END_HDL,
};
uint8_t qiot_write_cback(dmConnId_t connId, uint16_t handle, uint8_t operation,
uint16_t offset, uint16_t len, uint8_t *pValue, attsAttr_t *pAttr)
{
// SEGGER_RTT_printf(0, "id %d, hd %d, op %d, of %d \r\n", connId, handle, operation, offset);
// if(pAttr != NULL)
// {
// SEGGER_RTT_printf(0, "uuid %d %d, ml %d, set %d, per %d \r\n",
// pAttr->pUuid[0],
// pAttr->pUuid[1],
// pAttr->maxLen,
// pAttr->settings,
// pAttr->permissions);
// }
switch (handle)
{
case QIOT_DEVICE_INFO_HDL:
ble_device_info_write_cb(pValue, len);
break;
case QIOT_DATA_HDL:
ble_lldata_write_cb(pValue, len);
break;
case QIOT_EVENT_HDL:
break;
default:
break;
}
return ATT_SUCCESS;
}
void ble_services_add(const qiot_service_init_s *p_service)
{
qiot_attr_group.writeCback = qiot_write_cback;
AttsAddGroup(&qiot_attr_group);
// return 0;
}
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)
{
mac[0] = 0x99;
mac[1] = 0x98;
mac[2] = 0x97;
mac[3] = 0x96;
mac[4] = 0x95;
mac[5] = 0x94;
return 0;
}
// eeprom simulation
uint8_t eeprom[256] = {0};
int ble_write_flash(uint32_t flash_addr, const char *write_buf, uint16_t write_len)
{
memcpy(eeprom, write_buf, write_len);
return write_len;
}
int ble_read_flash(uint32_t flash_addr, char *read_buf, uint16_t read_len)
{
memcpy(read_buf, eeprom, read_len);
return read_len;
}
ble_qiot_ret_status_t ble_advertising_start(adv_info_s *adv)
{
uint8_t adv_data[31] = {0};
uint8_t scan_data[31] = {0};
int adv_p = 0;
int scan_p = 0;
// adv flag
adv_data[adv_p++] = 2;// length
adv_data[adv_p++] = DM_ADV_TYPE_FLAGS;// AD type
adv_data[adv_p++] = DM_FLAG_LE_GENERAL_DISC | DM_FLAG_LE_BREDR_NOT_SUP;// flags
// adv deivce name
// adv_data[adv_p++] = strlen(ADV_DEVICE_NAME) + 1; // length
// adv_data[adv_p++] = DM_ADV_TYPE_LOCAL_NAME;
// strncpy(&adv_data[adv_p], ADV_DEVICE_NAME, 31 - adv_p);
// adv_p += strlen(ADV_DEVICE_NAME);
scan_data[scan_p++] = strlen(ADV_DEVICE_NAME) + 1; // length
scan_data[scan_p++] = DM_ADV_TYPE_LOCAL_NAME;
strncpy((char *)&scan_data[scan_p], ADV_DEVICE_NAME, 31 - scan_p);
scan_p += strlen(ADV_DEVICE_NAME);
// Complete list of 16 bit UUIDs
adv_data[adv_p++] = 3;
adv_data[adv_p++] = DM_ADV_TYPE_16_UUID;
adv_data[adv_p++] = (uint8_t)adv->uuid_info.uuids[0];
adv_data[adv_p++] = (uint8_t)(adv->uuid_info.uuids[0] >> 8);
// adv manufacture data
adv_data[adv_p++] = adv->manufacturer_info.adv_data_len + 3;
adv_data[adv_p++] = DM_ADV_TYPE_MANUFACTURER;
adv_data[adv_p++] = (uint8_t)adv->manufacturer_info.company_identifier;
adv_data[adv_p++] = (uint8_t)(adv->manufacturer_info.company_identifier >> 8);
memcpy(&adv_data[adv_p], adv->manufacturer_info.adv_data, adv->manufacturer_info.adv_data_len);
adv_p += adv->manufacturer_info.adv_data_len;
// HexDump("adv", adv_data, sizeof(adv_data));
// AppAdvSetAdValue();
/* set advertising and scan response data for discoverable mode */
AppAdvSetData(APP_ADV_DATA_DISCOVERABLE, adv_p, (uint8_t *) adv_data);
// AppAdvSetData(APP_SCAN_DATA_DISCOVERABLE, sizeof(watchScanDataDisc), (uint8_t *) watchScanDataDisc);
AppAdvSetData(APP_SCAN_DATA_DISCOVERABLE, scan_p, (uint8_t *)scan_data);
/* set advertising and scan response data for connectable mode */
AppAdvSetData(APP_ADV_DATA_CONNECTABLE, 0, NULL);
AppAdvSetData(APP_SCAN_DATA_CONNECTABLE, 0, NULL);
/* start advertising; automatically set connectable/discoverable mode and bondable mode */
AppAdvStart(APP_MODE_AUTO_INIT);
return BLE_QIOT_RS_OK;
}
ble_qiot_ret_status_t ble_advertising_stop(void)
{
AppAdvStop();
return BLE_QIOT_RS_OK;
}
dmConnId_t ind_conn_id = DM_CONN_ID_NONE;
ble_qiot_ret_status_t ble_send_notify(uint8_t *buf, uint8_t len)
{
AttsHandleValueNtf(ind_conn_id, QIOT_EVENT_HDL, len, buf);
return BLE_QIOT_RS_OK;
}
static wsfTimer_t ble_qiot_timer;
ble_timer_cb p_ble_timer_cb = NULL;
ble_timer_t ble_timer_create(uint8_t type, ble_timer_cb timeout_handle)
{
ble_qiot_timer.handlerId = get_wsf_evt_handler();
p_ble_timer_cb = timeout_handle;
return (ble_timer_t)&ble_qiot_timer;
}
ble_qiot_ret_status_t ble_timer_start(ble_timer_t timer_id, uint32_t period)
{
WsfTimerStartMs((wsfTimer_t *)timer_id, period);
return BLE_QIOT_RS_OK;
}
ble_qiot_ret_status_t ble_timer_stop(ble_timer_t timer_id)
{
WsfTimerStop((wsfTimer_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)
{
return AttGetMtu(ind_conn_id) - 3;
}

View File

@@ -0,0 +1,47 @@
/*
* 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 __APOLLO3_SERVICE_H
#define __APOLLO3_SERVICE_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include "ble_qiot_export.h"
#define QIOT_START_HDL 0x0501 // do not start from 1, gap/gatt characteristic use some hdl from 1
#define QIOT_END_HDL (QIOT_MAX_HDL - 1)
enum
{
QIOT_SVC_HDL = QIOT_START_HDL,
QIOT_DEVICE_INFO_CHAR_HDL,
QIOT_DEVICE_INFO_HDL,
QIOT_DATA_CHAR_HDL,
QIOT_DATA_HDL,
QIOT_EVENT_CHAR_HDL,
QIOT_EVENT_HDL,
QIOT_EVENT_CCC_HDL,
QIOT_MAX_HDL,
};
void ble_services_add(const qiot_service_init_s *p_service);
#ifdef __cplusplus
}
#endif
#endif // __APOLLO3_SERVICE_H

View File

@@ -0,0 +1,70 @@
/*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
* Licensed under the MIT License (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://opensource.org/licenses/MIT
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#ifndef QCLOUD_BLE_QIOT_CONFIG_H
#define QCLOUD_BLE_QIOT_CONFIG_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdio.h>
#include <stdint.h>
#include "SEGGER_RTT.h"
#define BLE_QIOT_SDK_VERSION "1.1.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 1
#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__
#define BLE_QIOT_POST_BASE64 1
// 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(...) SEGGER_RTT_printf(0, __VA_ARGS__)
// some sdk info needs to stored on the device and the address is up to you
#define BLE_QIOT_RECORD_FLASH_ADDR 0x3f000
#ifdef __cplusplus
}
#endif
#endif // QCLOUD_BLE_QIOT_CONFIG_H

View File

@@ -0,0 +1,195 @@
//*****************************************************************************
//
//! @file ble_freertos_watch.c
//!
//! @brief ARM Cordio BLE - Concurrent Master/Slave Example.
//!
//! Purpose: This example demonstrates an BLE application in the Central role.
//! That is the BLE application operates as a slave to phone master and as the
//! master of subordinate slave devices running freertos_fit example in this SDK.
//!
//! Additional Information:
//! 1. Printing takes place over the ITM at 1M Baud.
//! 2. When the example powers up,
//! 2.A. it enters advertising mode by default to wait for connection from
//! smart phone with Time profile, Alert Notification profile and Phone
//! Alert Status profile supported.
//! 2.B. when BTN2 on Apollo3 EVB is short-pressed, if advertising is on, it
//! stops advertising first and then starts scanning when advertising is
//! stopped; if scanning is on, it stops scanning and re-start advertising
//! when scanning stops.
//! 2.C. During scanning, the device (if discovered) running freertos_fit
//! example in this SDK will be connected and scanning will be stopped.
//! 2.D. Repeat 2.B. and 2.C. above to connect to a new slave device running
//! freertos_fit example (max slaves is 3).
//! 3. when phone (iPhone is used) connects to this example, the services of Time
//! profile, Alert Notification profile and Phone Alert Status profile will be
// subscribed by the example.
//
//*****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// 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 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 the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// 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 THE COPYRIGHT HOLDER 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.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
//*****************************************************************************
//
// This application has a large number of common include files. For
// convenience, we'll collect them all together in a single header and include
// that everywhere.
//
//*****************************************************************************
#include "ble_qiot_demo.h"
#include "rtos.h"
#include "SEGGER_RTT.h"
#include "ble_qiot_export.h"
//*****************************************************************************
//
// Enable printing to the console.
//
//*****************************************************************************
void
enable_print_interface(void)
{
//
// Initialize a debug printing interface.
//
am_bsp_itm_printf_enable();
}
//*****************************************************************************
//
// Main Function
//
//*****************************************************************************
int
main(void)
{
SEGGER_RTT_ConfigUpBuffer(0, NULL, NULL, 0, SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL);
// SEGGER_RTT_ConfigUpBuffer(0, NULL, NULL, 0, SEGGER_RTT_MODE_NO_BLOCK_SKIP);
SEGGER_RTT_WriteString(0, ">>>> Tencent ble qiot demo start <<<<\r\n");
//
// Set the clock frequency
//
am_hal_clkgen_control(AM_HAL_CLKGEN_CONTROL_SYSCLK_MAX, 0);
//
// Set the default cache configuration
//
am_hal_cachectrl_config(&am_hal_cachectrl_defaults);
am_hal_cachectrl_enable();
#ifndef NOFPU
//
// Enable the floating point module, and configure the core for lazy
// stacking.
//
am_hal_sysctrl_fpu_enable();
am_hal_sysctrl_fpu_stacking_enable(true);
#else
am_hal_sysctrl_fpu_disable();
#endif
//
// Configure the board for low power.
//
am_bsp_low_power_init();
// Turn off unused Flash & SRAM
#ifdef AM_PART_APOLLO
//
// SRAM bank power setting.
// Need to match up with actual SRAM usage for the program
// Current usage is between 32K and 40K - so disabling upper 3 banks
//
am_hal_mcuctrl_sram_power_set(AM_HAL_MCUCTRL_SRAM_POWER_DOWN_5 |
AM_HAL_MCUCTRL_SRAM_POWER_DOWN_6 |
AM_HAL_MCUCTRL_SRAM_POWER_DOWN_7,
AM_HAL_MCUCTRL_SRAM_POWER_DOWN_5 |
AM_HAL_MCUCTRL_SRAM_POWER_DOWN_6 |
AM_HAL_MCUCTRL_SRAM_POWER_DOWN_7);
#if 0 // Not turning off the Flash as it may be needed to download the image
//
// Flash bank power set.
//
am_hal_mcuctrl_flash_power_set(AM_HAL_MCUCTRL_FLASH_POWER_DOWN_1);
#endif
#endif // AM_PART_APOLLO
#ifdef AM_PART_APOLLO2
#if 0 // Not turning off the Flash as it may be needed to download the image
am_hal_pwrctrl_memory_enable(AM_HAL_PWRCTRL_MEMEN_FLASH512K);
#endif
am_hal_pwrctrl_memory_enable(AM_HAL_PWRCTRL_MEMEN_SRAM64K);
#endif // AM_PART_APOLLO2
//
// Enable printing to the console.
//
#ifdef AM_DEBUG_PRINTF
enable_print_interface();
#endif
//
// Initialize plotting interface.
//
am_util_debug_printf("FreeRTOS Watch Example\n");
// ble_services_add(service_info);
// ble_qiot_explorer_init();
// conn_params_init();
//
// Run the application.
//
run_tasks();
//
// We shouldn't ever get here.
//
while (1)
{
}
}

View File

@@ -0,0 +1,89 @@
//*****************************************************************************
//
//! @file freertos_fit.h
//!
//! @brief Global includes for the freertos_fit app.
//
//*****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// 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 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 the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// 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 THE COPYRIGHT HOLDER 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.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
#ifndef FREERTOS_WATCH_H
#define FREERTOS_WATCH_H
//*****************************************************************************
//
// Required built-ins.
//
//*****************************************************************************
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <stdlib.h>
//*****************************************************************************
//
// Standard AmbiqSuite includes.
//
//*****************************************************************************
#include "am_mcu_apollo.h"
#include "am_bsp.h"
#include "am_util.h"
//*****************************************************************************
//
// FreeRTOS include files.
//
//*****************************************************************************
#include "FreeRTOS.h"
#include "task.h"
#include "portmacro.h"
#include "portable.h"
#include "semphr.h"
#include "event_groups.h"
//#include "rtos.h"
//*****************************************************************************
//
// Task include files.
//
//*****************************************************************************
#include "radio_task.h"
#endif // FREERTOS_FIT_H

View File

@@ -0,0 +1,77 @@
//*****************************************************************************
//
//! @file hci_apollo_config.h
//!
//! @brief This file describes the physical aspects of the HCI conection.
//
//*****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// 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 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 the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// 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 THE COPYRIGHT HOLDER 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.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
#include <stdint.h>
#include "am_bsp.h"
#ifndef HCI_APOLLO_CONFIG_H
#define HCI_APOLLO_CONFIG_H
//*****************************************************************************
//
// Pin numbers and configuration.
//
// NOTE: RTS, CTS, and RESET are implemented as GPIOs, so no "CFG" field is
// needed.
//
//*****************************************************************************
//#define HCI_APOLLO_POWER_PIN AM_BSP_GPIO_EM9304_POWER
//#define HCI_APOLLO_POWER_CFG AM_BSP_GPIO_CFG_EM9304_POWER
#define HCI_APOLLO_RESET_PIN AM_BSP_GPIO_EM9304_RESET
//*****************************************************************************
//
// Other options.
//
// These options are provided in case your board setup is a little more
// unusual. Most boards shouldn't need these features. If in doubt, leave all
// of these features disabled.
//
//*****************************************************************************
#define HCI_APOLLO_CFG_OVERRIDE_ISR 1 // Override the exactle UART ISR
#endif // HCI_APOLLO_CONFIG_H

View File

@@ -0,0 +1,403 @@
//*****************************************************************************
//
//! @file radio_task.c
//!
//! @brief Task to handle radio operation.
//!
//*****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// 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 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 the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// 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 THE COPYRIGHT HOLDER 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.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
//*****************************************************************************
//
// Global includes for this project.
//
//*****************************************************************************
#include "ble_qiot_demo.h"
//*****************************************************************************
//
// WSF standard includes.
//
//*****************************************************************************
#include "wsf_types.h"
#include "wsf_trace.h"
#include "wsf_buf.h"
#include "wsf_timer.h"
//*****************************************************************************
//
// Includes for operating the ExactLE stack.
//
//*****************************************************************************
#include "hci_handler.h"
#include "dm_handler.h"
#include "l2c_handler.h"
#include "att_handler.h"
#include "smp_handler.h"
#include "l2c_api.h"
#include "att_api.h"
#include "smp_api.h"
#include "app_api.h"
#include "hci_core.h"
#include "hci_drv.h"
#include "hci_drv_apollo.h"
#include "hci_drv_apollo3.h"
#include "hci_apollo_config.h"
#include "wsf_msg.h"
//*****************************************************************************
//
//
//*****************************************************************************
#include "watch_api.h"
#include "app_ui.h"
//*****************************************************************************
//
// Radio task handle.
//
//*****************************************************************************
TaskHandle_t radio_task_handle;
//*****************************************************************************
//
// Function prototypes
//
//*****************************************************************************
void exactle_stack_init(void);
void button_handler(wsfEventMask_t event, wsfMsgHdr_t *pMsg);
void setup_buttons(void);
//*****************************************************************************
//
// Timer for buttons.
//
//*****************************************************************************
wsfHandlerId_t ButtonHandlerId;
wsfTimer_t ButtonTimer;
//*****************************************************************************
//
// WSF buffer pools.
//
//*****************************************************************************
#define WSF_BUF_POOLS 4
// Important note: the size of g_pui32BufMem should includes both overhead of internal
// buffer management structure, wsfBufPool_t (up to 16 bytes for each pool), and pool
// description (e.g. g_psPoolDescriptors below).
// Memory for the buffer pool
// extra AMOTA_PACKET_SIZE bytes for OTA handling
static uint32_t g_pui32BufMem[
(WSF_BUF_POOLS*16
+ 16*8 + 32*4 + 64*6 + 280*8) / sizeof(uint32_t)];
// Default pool descriptor.
static wsfBufPoolDesc_t g_psPoolDescriptors[WSF_BUF_POOLS] =
{
{ 16, 8 },
{ 32, 4 },
{ 64, 6 },
{ 280, 8 }
};
//*****************************************************************************
//
// Tracking variable for the scheduler timer.
//
//*****************************************************************************
void radio_timer_handler(void);
//*****************************************************************************
//
// Poll the buttons.
//
//*****************************************************************************
void
button_handler(wsfEventMask_t event, wsfMsgHdr_t *pMsg)
{
//
// Restart the button timer.
//
WsfTimerStartMs(&ButtonTimer, 10);
//
// Every time we get a button timer tick, check all of our buttons.
//
am_devices_button_array_tick(am_bsp_psButtons, AM_BSP_NUM_BUTTONS);
//
// If we got a a press, do something with it.
//
if ( am_devices_button_released(am_bsp_psButtons[0]) )
{
am_util_debug_printf("Got Button 0 Press\n");
AppUiBtnTest(APP_UI_BTN_1_SHORT);
}
if ( am_devices_button_released(am_bsp_psButtons[1]) )
{
am_util_debug_printf("Got Button 1 Press\n");
AppUiBtnTest(APP_UI_BTN_1_SHORT);
}
if ( am_devices_button_released(am_bsp_psButtons[2]) )
{
am_util_debug_printf("Got Button 2 Press\n");
}
}
//*****************************************************************************
//
// Sets up a button interface.
//
//*****************************************************************************
void
setup_buttons(void)
{
//
// Enable the buttons for user interaction.
//
am_devices_button_array_init(am_bsp_psButtons, AM_BSP_NUM_BUTTONS);
//
// Start a timer.
//
ButtonTimer.handlerId = ButtonHandlerId;
WsfTimerStartSec(&ButtonTimer, 2);
}
//*****************************************************************************
//
// Initialization for the ExactLE stack.
//
//*****************************************************************************
void
exactle_stack_init(void)
{
wsfHandlerId_t handlerId;
uint16_t wsfBufMemLen;
//
// Set up timers for the WSF scheduler.
//
WsfOsInit();
WsfTimerInit();
//
// Initialize a buffer pool for WSF dynamic memory needs.
//
wsfBufMemLen = WsfBufInit(sizeof(g_pui32BufMem), (uint8_t *)g_pui32BufMem, WSF_BUF_POOLS,
g_psPoolDescriptors);
if (wsfBufMemLen > sizeof(g_pui32BufMem))
{
am_util_debug_printf("Memory pool is too small by %d\r\n",
wsfBufMemLen - sizeof(g_pui32BufMem));
}
//
// Initialize the WSF security service.
//
SecInit();
SecAesInit();
SecCmacInit();
SecEccInit();
//
// Set up callback functions for the various layers of the ExactLE stack.
//
handlerId = WsfOsSetNextHandler(HciHandler);
HciHandlerInit(handlerId);
handlerId = WsfOsSetNextHandler(DmHandler);
DmDevVsInit(0);
DmAdvInit();
DmScanInit();
DmConnInit();
DmConnMasterInit();
DmConnSlaveInit();
DmSecInit();
DmSecLescInit();
DmPrivInit();
DmHandlerInit(handlerId);
handlerId = WsfOsSetNextHandler(L2cSlaveHandler);
L2cSlaveHandlerInit(handlerId);
L2cInit();
L2cSlaveInit();
L2cMasterInit();
handlerId = WsfOsSetNextHandler(AttHandler);
AttHandlerInit(handlerId);
AttsInit();
AttsIndInit();
AttcInit();
handlerId = WsfOsSetNextHandler(SmpHandler);
SmpHandlerInit(handlerId);
SmpiInit();
SmpiScInit();
SmprInit();
SmprScInit();
HciSetMaxRxAclLen(251);
handlerId = WsfOsSetNextHandler(AppHandler);
AppHandlerInit(handlerId);
handlerId = WsfOsSetNextHandler(WatchHandler);
WatchHandlerInit(handlerId);
handlerId = WsfOsSetNextHandler(HciDrvHandler);
HciDrvHandlerInit(handlerId);
ButtonHandlerId = WsfOsSetNextHandler(button_handler);
}
//*****************************************************************************
//
// UART interrupt handler.
//
//*****************************************************************************
void
am_uart_isr(void)
{
uint32_t ui32Status;
//
// Read and save the interrupt status, but clear out the status register.
//
ui32Status = UARTn(0)->MIS;
UARTn(0)->IEC = ui32Status;
//
// Allow the HCI driver to respond to the interrupt.
//
//HciDrvUartISR(ui32Status);
// Signal radio task to run
WsfTaskSetReady(0, 0);
}
//*****************************************************************************
//
// Interrupt handler for BLE
//
//*****************************************************************************
void
am_ble_isr(void)
{
HciDrvIntService();
// Signal radio task to run
WsfTaskSetReady(0, 0);
}
//*****************************************************************************
//
// Perform initial setup for the radio task.
//
//*****************************************************************************
void
RadioTaskSetup(void)
{
am_util_debug_printf("RadioTask: setup\r\n");
NVIC_SetPriority(BLE_IRQn, NVIC_configMAX_SYSCALL_INTERRUPT_PRIORITY);
//
// Boot the radio.
//
HciDrvRadioBoot(1);
}
//*****************************************************************************
//
// Short Description.
//
//*****************************************************************************
void
RadioTask(void *pvParameters)
{
#if WSF_TRACE_ENABLED == TRUE
//
// Enable ITM
//
am_util_debug_printf("Starting wicentric trace:\n\n");
#endif
//
// Initialize the main ExactLE stack.
//
exactle_stack_init();
//
// Prep the buttons for use
//
setup_buttons();
//
// Start the "Ancs" profile.
//
WatchStart();
while (1)
{
//
// Calculate the elapsed time from our free-running timer, and update
// the software timers in the WSF scheduler.
//
wsfOsDispatcher();
}
}

View File

@@ -0,0 +1,65 @@
//*****************************************************************************
//
//! @file radio_task.h
//!
//! @brief Functions and variables related to the radio task.
//!
//*****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// 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 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 the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// 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 THE COPYRIGHT HOLDER 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.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
#ifndef RADIO_TASK_H
#define RADIO_TASK_H
//*****************************************************************************
//
// Radio task handle.
//
//*****************************************************************************
extern TaskHandle_t radio_task_handle;
//*****************************************************************************
//
// External function definitions.
//
//*****************************************************************************
extern void RadioTaskSetup(void);
extern void RadioTask(void *pvParameters);
#endif // RADIO_TASK_H

View File

@@ -0,0 +1,214 @@
//*****************************************************************************
//
//! @file rtos.c
//!
//! @brief Essential functions to make the RTOS run correctly.
//!
//! These functions are required by the RTOS for ticking, sleeping, and basic
//! error checking.
//
//*****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// 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 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 the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// 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 THE COPYRIGHT HOLDER 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.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
#include <stdint.h>
#include <stdbool.h>
#include "am_mcu_apollo.h"
#include "am_bsp.h"
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "portmacro.h"
#include "portable.h"
#include "ble_qiot_demo.h"
//*****************************************************************************
//
// Task handle for the initial setup task.
//
//*****************************************************************************
TaskHandle_t xSetupTask;
//*****************************************************************************
//
// Interrupt handler for the CTIMER module.
//
//*****************************************************************************
void
am_ctimer_isr(void)
{
uint32_t ui32Status;
//
// Check the timer interrupt status.
//
ui32Status = am_hal_ctimer_int_status_get(false);
am_hal_ctimer_int_clear(ui32Status);
//
// Run handlers for the various possible timer events.
//
am_hal_ctimer_int_service(ui32Status);
}
//*****************************************************************************
//
// Sleep function called from FreeRTOS IDLE task.
// Do necessary application specific Power down operations here
// Return 0 if this function also incorporates the WFI, else return value same
// as idleTime
//
//*****************************************************************************
uint32_t am_freertos_sleep(uint32_t idleTime)
{
am_hal_sysctrl_sleep(AM_HAL_SYSCTRL_SLEEP_DEEP);
return 0;
}
//*****************************************************************************
//
// Recovery function called from FreeRTOS IDLE task, after waking up from Sleep
// Do necessary 'wakeup' operations here, e.g. to power up/enable peripherals etc.
//
//*****************************************************************************
void am_freertos_wakeup(uint32_t idleTime)
{
return;
}
//*****************************************************************************
//
// FreeRTOS debugging functions.
//
//*****************************************************************************
void
vApplicationMallocFailedHook(void)
{
//
// Called if a call to pvPortMalloc() fails because there is insufficient
// free memory available in the FreeRTOS heap. pvPortMalloc() is called
// internally by FreeRTOS API functions that create tasks, queues, software
// timers, and semaphores. The size of the FreeRTOS heap is set by the
// configTOTAL_HEAP_SIZE configuration constant in FreeRTOSConfig.h.
//
while (1);
}
void
vApplicationStackOverflowHook(TaskHandle_t pxTask, char *pcTaskName)
{
(void) pcTaskName;
(void) pxTask;
//
// Run time stack overflow checking is performed if
// configconfigCHECK_FOR_STACK_OVERFLOW is defined to 1 or 2. This hook
// function is called if a stack overflow is detected.
//
while (1)
{
__asm("BKPT #0\n") ; // Break into the debugger
}
}
//*****************************************************************************
//
// High priority task to run immediately after the scheduler starts.
//
// This task is used for any global initialization that must occur after the
// scheduler starts, but before any functional tasks are running. This can be
// useful for enabling events, semaphores, and other global, RTOS-specific
// features.
//
//*****************************************************************************
void
setup_task(void *pvParameters)
{
//
// Print a debug message.
//
am_util_debug_printf("Running setup tasks...\r\n");
//
// Run setup functions.
//
RadioTaskSetup();
//
// Create the functional tasks
//
xTaskCreate(RadioTask, "RadioTask", 512, 0, 3, &radio_task_handle);
//
// The setup operations are complete, so suspend the setup task now.
//
vTaskSuspend(NULL);
while (1);
}
//*****************************************************************************
//
// Initializes all tasks
//
//*****************************************************************************
void
run_tasks(void)
{
//
// Set some interrupt priorities before we create tasks or start the scheduler.
//
// Note: Timer priority is handled by the FreeRTOS kernel, so we won't
// touch it here.
//
//
// Create essential tasks.
//
xTaskCreate(setup_task, "Setup", 512, 0, 3, &xSetupTask);
//
// Start the scheduler.
//
vTaskStartScheduler();
}

View File

@@ -0,0 +1,75 @@
//*****************************************************************************
//
//! @file rtos.h
//!
//! @brief Essential functions to make the RTOS run
//
//*****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// 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 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 the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// 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 THE COPYRIGHT HOLDER 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.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
#ifndef RTOS_H
#define RTOS_H
#ifdef __cplusplus
extern "C"
{
#endif
//*****************************************************************************
//
// Macro definitions
//
//*****************************************************************************
// External variable definitions
//
//*****************************************************************************
//*****************************************************************************
//
// External function definitions
//
//*****************************************************************************
void run_tasks(void);
#ifdef __cplusplus
}
#endif
#endif // RTOS_H

View File

@@ -0,0 +1,80 @@
/*************************************************************************************************/
/*!
* \file
*
* \brief Watch sample application interface.
*
* Copyright (c) 2011-2018 Arm Ltd.
*
* Copyright (c) 2019 Packetcraft, Inc.
*
* Licensed 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.
*/
/*************************************************************************************************/
#ifndef WATCH_API_H
#define WATCH_API_H
#include "wsf_os.h"
#ifdef __cplusplus
extern "C" {
#endif
/**************************************************************************************************
Function Declarations
**************************************************************************************************/
/*************************************************************************************************/
/*!
* \brief Start the application.
*
* \return None.
*/
/*************************************************************************************************/
void WatchStart(void);
/*************************************************************************************************/
/*!
* \brief Application handler init function called during system initialization.
*
* \param handlerID WSF handler ID for App.
*
* \return None.
*/
/*************************************************************************************************/
void WatchHandlerInit(wsfHandlerId_t handlerId);
/*************************************************************************************************/
/*!
* \brief WSF event handler for the application.
*
* \param event WSF event mask.
* \param pMsg WSF message.
*
* \return None.
*/
/*************************************************************************************************/
void WatchHandler(wsfEventMask_t event, wsfMsgHdr_t *pMsg);
/**
* @brief Get the handler object of WSF event handler for the application
*
* @return wsfHandlerId_t
*/
wsfHandlerId_t get_wsf_evt_handler(void);
#ifdef __cplusplus
};
#endif
#endif /* WATCH_API_H */

View File

@@ -0,0 +1,535 @@
/*
* 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 "ble_qiot_export.h"
#include "ble_qiot_common.h"
#include "ble_qiot_param_check.h"
#include "ble_qiot_ble_device.h"
static uint8_t sg_test_power_switch = false;
static int ble_property_power_switch_set(const char *data, uint16_t len)
{
ble_qiot_log_d("set property power_switch %d", *(uint8_t *)data);
property_power_switch(data, len);
sg_test_power_switch = data[0];
return 0;
}
static int ble_property_power_switch_get(char *data, uint16_t buf_len)
{
ble_qiot_log_d("get property power_switch %d", sg_test_power_switch);
data[0] = sg_test_power_switch;
return sizeof(uint8_t);
}
static uint16_t sg_test_color = 0;
static int ble_property_color_set(const char *data, uint16_t len)
{
uint16_t color_value = 0;
memcpy(&color_value, data, sizeof(uint16_t));
color_value = NTOHS(color_value);
ble_qiot_log_d("set property color %d", color_value);
sg_test_color = color_value;
return 0;
}
static int ble_property_color_get(char *data, uint16_t buf_len)
{
uint16_t color_value = 0;
ble_qiot_log_d("get property color %d", color_value);
color_value = HTONS(sg_test_color);
memcpy(data, &color_value, sizeof(uint16_t));
return sizeof(uint16_t);
}
static int sg_test_brightness = 0;
static int ble_property_brightness_set(const char *data, uint16_t len)
{
int brightness_value = 0;
memcpy(&brightness_value, data, sizeof(int));
brightness_value = NTOHL(brightness_value);
if ((brightness_value < BLE_QIOT_PROPERTY_BRIGHTNESS_MIN) ||
(brightness_value > BLE_QIOT_PROPERTY_BRIGHTNESS_MAX)) {
ble_qiot_log_e("invalid brightness value %d", brightness_value);
return -1;
}
ble_qiot_log_d("set property brightness %d", brightness_value);
sg_test_brightness = brightness_value;
return 0;
}
static int ble_property_brightness_get(char *data, uint16_t buf_len)
{
int brightness_value = 0;
ble_qiot_log_d("get property brightness %d", sg_test_brightness);
brightness_value = HTONL(sg_test_brightness);
memcpy(data, &brightness_value, sizeof(int));
return sizeof(uint32_t);
}
static char sg_test_name[100 + 1] = "default name";
static int ble_property_name_set(const char *data, uint16_t len)
{
ble_qiot_log_d("set property name %.*s", len, data);
if (len > sizeof(sg_test_name) - 1) {
ble_qiot_log_d("too long name");
return -1;
}
memset(sg_test_name, 0, sizeof(sg_test_name));
memcpy(sg_test_name, data, len);
return 0;
}
static int ble_property_name_get(char *data, uint16_t buf_len)
{
int i = 0;
ble_qiot_log_d("get property name %s", sg_test_name);
if (0 == strncmp("default name", sg_test_name, sizeof("default name") - 1)) {
for (i = 0; i < 26 * 3; i++) {
data[i] = 'a' + (i % 26);
}
return i;
} else {
memcpy(data, sg_test_name, strlen(sg_test_name));
return strlen(sg_test_name);
}
}
static ble_property_t sg_ble_property_array[BLE_QIOT_PROPERTY_ID_BUTT] = {
{ble_property_power_switch_set, ble_property_power_switch_get, BLE_QIOT_PROPERTY_AUTH_RW, BLE_QIOT_DATA_TYPE_BOOL},
{ble_property_color_set, ble_property_color_get, BLE_QIOT_PROPERTY_AUTH_RW, BLE_QIOT_DATA_TYPE_ENUM},
{ble_property_brightness_set, ble_property_brightness_get, BLE_QIOT_PROPERTY_AUTH_RW, BLE_QIOT_DATA_TYPE_INT},
{ble_property_name_set, ble_property_name_get, BLE_QIOT_PROPERTY_AUTH_RW, BLE_QIOT_DATA_TYPE_STRING},
};
static bool ble_check_space_enough_by_type(uint8_t type, uint16_t left_size)
{
switch (type) {
case BLE_QIOT_DATA_TYPE_BOOL:
return left_size >= sizeof(uint8_t);
case BLE_QIOT_DATA_TYPE_INT:
case BLE_QIOT_DATA_TYPE_FLOAT:
case BLE_QIOT_DATA_TYPE_TIME:
return left_size >= sizeof(uint32_t);
case BLE_QIOT_DATA_TYPE_ENUM:
return left_size >= sizeof(uint16_t);
default:
// string length is unknow, default true
return true;
}
}
static uint16_t ble_check_ret_value_by_type(uint8_t type, uint16_t buf_len, uint16_t ret_val)
{
switch (type) {
case BLE_QIOT_DATA_TYPE_BOOL:
return ret_val <= sizeof(uint8_t);
case BLE_QIOT_DATA_TYPE_INT:
case BLE_QIOT_DATA_TYPE_FLOAT:
case BLE_QIOT_DATA_TYPE_TIME:
return ret_val <= sizeof(uint32_t);
case BLE_QIOT_DATA_TYPE_ENUM:
return ret_val <= sizeof(uint16_t);
default:
// string length is unknow, default true
return ret_val <= buf_len;
}
}
uint8_t ble_get_property_type_by_id(uint8_t id)
{
if (id >= BLE_QIOT_PROPERTY_ID_BUTT) {
ble_qiot_log_e("invalid property id %d", id);
return BLE_QIOT_DATA_TYPE_BUTT;
}
return sg_ble_property_array[id].type;
}
int ble_user_property_set_data(const e_ble_tlv *tlv)
{
POINTER_SANITY_CHECK(tlv, BLE_QIOT_RS_ERR_PARA);
if (tlv->id >= BLE_QIOT_PROPERTY_ID_BUTT) {
ble_qiot_log_e("invalid property id %d", tlv->id);
return BLE_QIOT_RS_ERR;
}
if (NULL != sg_ble_property_array[tlv->id].set_cb) {
if (0 != sg_ble_property_array[tlv->id].set_cb(tlv->val, tlv->len)) {
ble_qiot_log_e("set property id %d failed", tlv->id);
return BLE_QIOT_RS_ERR;
} else {
return BLE_QIOT_RS_OK;
}
}
ble_qiot_log_e("invalid set callback, id %d", tlv->id);
return BLE_QIOT_RS_ERR;
}
int ble_user_property_get_data_by_id(uint8_t id, char *buf, uint16_t buf_len)
{
int ret_len = 0;
POINTER_SANITY_CHECK(buf, BLE_QIOT_RS_ERR_PARA);
if (id >= BLE_QIOT_PROPERTY_ID_BUTT) {
ble_qiot_log_e("invalid property id %d", id);
return -1;
}
if (NULL != sg_ble_property_array[id].get_cb) {
if (!ble_check_space_enough_by_type(sg_ble_property_array[id].type, buf_len)) {
ble_qiot_log_e("not enough space get property id %d data", id);
return -1;
}
ret_len = sg_ble_property_array[id].get_cb(buf, buf_len);
if (ret_len < 0) {
ble_qiot_log_e("get property id %d data failed", id);
return -1;
} else {
if (ble_check_ret_value_by_type(sg_ble_property_array[id].type, buf_len, ret_len)) {
return ret_len;
} else {
ble_qiot_log_e("property id %d length invalid, type %d", id, sg_ble_property_array[id].type);
return -1;
}
}
}
ble_qiot_log_e("invalid callback, property id %d", id);
return 0;
}
int ble_user_property_report_reply_handle(uint8_t result)
{
ble_qiot_log_d("report reply result %d", result);
if (0 == result) {
report_reply_blink();
}
return BLE_QIOT_RS_OK;
}
static int ble_event_get_status_report_status(char *buf, uint16_t buf_len)
{
buf[0] = 1;
return 1;
}
static int ble_event_get_status_report_message(char *buf, uint16_t buf_len)
{
int i = 0;
for (i = 0; i < 26 * 3; i++) {
buf[i] = 'a' + (i % 26);
}
return i;
}
static ble_event_param sg_ble_event_status_report_array[BLE_QIOT_EVENT_STATUS_REPORT_PARAM_ID_BUTT] = {
{ble_event_get_status_report_status, BLE_QIOT_DATA_TYPE_BOOL},
{ble_event_get_status_report_message, BLE_QIOT_DATA_TYPE_STRING},
};
static int ble_event_get_low_voltage_voltage(char *data, uint16_t buf_len)
{
float tmp = 1.0;
memcpy(data, &tmp, sizeof(float));
return sizeof(float);
}
static ble_event_param sg_ble_event_low_voltage_array[BLE_QIOT_EVENT_LOW_VOLTAGE_PARAM_ID_BUTT] = {
{ble_event_get_low_voltage_voltage, BLE_QIOT_DATA_TYPE_FLOAT},
};
static int ble_event_get_hardware_fault_name(char *data, uint16_t buf_len)
{
memcpy(data, "hardware_fault", sizeof("hardware_fault") - 1);
return sizeof("hardware_fault") - 1;
}
static int ble_event_get_hardware_fault_error_code(char *data, uint16_t buf_len)
{
int error_code = HTONL(1024);
memcpy(data, &error_code, sizeof(int));
return sizeof(int);
}
static ble_event_param sg_ble_event_hardware_fault_array[BLE_QIOT_EVENT_HARDWARE_FAULT_PARAM_ID_BUTT] = {
{ble_event_get_hardware_fault_name, BLE_QIOT_DATA_TYPE_STRING},
{ble_event_get_hardware_fault_error_code, BLE_QIOT_DATA_TYPE_INT},
};
static ble_event_t sg_ble_event_array[BLE_QIOT_EVENT_ID_BUTT] = {
{sg_ble_event_status_report_array, sizeof(sg_ble_event_status_report_array) / sizeof(ble_event_param)},
{sg_ble_event_low_voltage_array, sizeof(sg_ble_event_low_voltage_array) / sizeof(ble_event_param)},
{sg_ble_event_hardware_fault_array, sizeof(sg_ble_event_hardware_fault_array) / sizeof(ble_event_param)},
};
int ble_event_get_id_array_size(uint8_t event_id)
{
if (event_id >= BLE_QIOT_EVENT_ID_BUTT) {
ble_qiot_log_e("invalid event id %d", event_id);
return -1;
}
return sg_ble_event_array[event_id].array_size;
}
uint8_t ble_event_get_param_id_type(uint8_t event_id, uint8_t param_id)
{
if (event_id >= BLE_QIOT_EVENT_ID_BUTT) {
ble_qiot_log_e("invalid event id %d", event_id);
return BLE_QIOT_DATA_TYPE_BUTT;
}
if (param_id >= sg_ble_event_array[event_id].array_size) {
ble_qiot_log_e("invalid param id %d", param_id);
return BLE_QIOT_DATA_TYPE_BUTT;
}
return sg_ble_event_array[event_id].event_array[param_id].type;
}
int ble_event_get_data_by_id(uint8_t event_id, uint8_t param_id, char *out_buf, uint16_t buf_len)
{
int ret_len = 0;
if (event_id >= BLE_QIOT_EVENT_ID_BUTT) {
ble_qiot_log_e("invalid event id %d", event_id);
return -1;
}
if (param_id >= sg_ble_event_array[event_id].array_size) {
ble_qiot_log_e("invalid param id %d", param_id);
return -1;
}
if (NULL == sg_ble_event_array[event_id].event_array[param_id].get_cb) {
ble_qiot_log_e("invalid callback, event id %d, param id %d", event_id, param_id);
return 0;
}
if (!ble_check_space_enough_by_type(sg_ble_event_array[event_id].event_array[param_id].type, buf_len)) {
ble_qiot_log_e("not enough space get data, event id %d, param id %d", event_id, param_id);
return -1;
}
ret_len = sg_ble_event_array[event_id].event_array[param_id].get_cb(out_buf, buf_len);
if (ret_len < 0) {
ble_qiot_log_e("get event data failed, event id %d, param id %d", event_id, param_id);
return -1;
} else {
if (ble_check_ret_value_by_type(sg_ble_event_array[event_id].event_array[param_id].type, buf_len, ret_len)) {
return ret_len;
} else {
ble_qiot_log_e("evnet data length invalid, event id %d, param id %d, type %d", event_id, param_id,
sg_ble_event_array[event_id].event_array[param_id].type);
return -1;
}
}
}
int ble_user_event_reply_handle(uint8_t event_id, uint8_t result)
{
ble_qiot_log_d("event id %d, reply result %d", event_id, result);
return BLE_QIOT_RS_OK;
}
static int ble_action_handle_loop_input_cb(e_ble_tlv *input_param_array, uint8_t input_array_size,
uint8_t *output_id_array)
{
int result = 0;
if (NULL == input_param_array || NULL == output_id_array) {
ble_qiot_log_e("invalid param");
return -1;
}
report_reply_blink();
for (int i = 0; i < input_array_size; i++) {
ble_qiot_log_d("id %d", input_param_array[i].id);
}
memcpy(&result, input_param_array[0].val, sizeof(int));
result = NTOHL(result);
ble_qiot_log_d("id %d, val %d", input_param_array[0].id, result);
action_led_blink(result);
output_id_array[BLE_QIOT_ACTION_LOOP_OUTPUT_ID_RESULT] = true;
return 0;
}
static int ble_action_handle_loop_output_cb(uint8_t output_id, char *buf, uint16_t buf_len)
{
int data_len = 0;
int i = 0;
switch (output_id) {
case BLE_QIOT_ACTION_LOOP_OUTPUT_ID_RESULT:
for (i = 0; i < 26 * 3; i++) {
buf[i] = 'a' + (i % 26);
}
data_len = i;
break;
default:
break;
}
return data_len;
}
static uint8_t sg_ble_action_loop_input_type_array[BLE_QIOT_ACTION_LOOP_INPUT_ID_BUTT] = {
BLE_QIOT_DATA_TYPE_INT,
};
static uint8_t sg_ble_action_loop_output_type_array[BLE_QIOT_ACTION_LOOP_OUTPUT_ID_BUTT] = {
BLE_QIOT_DATA_TYPE_STRING,
};
static ble_action_t sg_ble_action_array[BLE_QIOT_ACTION_ID_BUTT] = {
{ble_action_handle_loop_input_cb, ble_action_handle_loop_output_cb, sg_ble_action_loop_input_type_array,
sg_ble_action_loop_output_type_array, sizeof(sg_ble_action_loop_input_type_array) / sizeof(uint8_t),
sizeof(sg_ble_action_loop_output_type_array) / sizeof(uint8_t)},
};
uint8_t ble_action_get_intput_type_by_id(uint8_t action_id, uint8_t input_id)
{
if (action_id >= BLE_QIOT_ACTION_ID_BUTT) {
ble_qiot_log_e("invalid action id %d", action_id);
return BLE_QIOT_DATA_TYPE_BUTT;
}
if (input_id >= sg_ble_event_array[action_id].array_size) {
ble_qiot_log_e("invalid input id %d", input_id);
return BLE_QIOT_DATA_TYPE_BUTT;
}
return sg_ble_action_array[action_id].input_type_array[input_id];
}
uint8_t ble_action_get_output_type_by_id(uint8_t action_id, uint8_t output_id)
{
if (action_id >= BLE_QIOT_ACTION_ID_BUTT) {
ble_qiot_log_e("invalid action id %d", action_id);
return BLE_QIOT_DATA_TYPE_BUTT;
}
if (output_id >= sg_ble_event_array[action_id].array_size) {
ble_qiot_log_e("invalid output id %d", output_id);
return BLE_QIOT_DATA_TYPE_BUTT;
}
return sg_ble_action_array[action_id].output_type_array[output_id];
}
int ble_action_get_input_id_size(uint8_t action_id)
{
if (action_id >= BLE_QIOT_ACTION_ID_BUTT) {
ble_qiot_log_e("invalid action id %d", action_id);
return -1;
}
return sg_ble_action_array[action_id].input_id_size;
}
int ble_action_get_output_id_size(uint8_t action_id)
{
if (action_id >= BLE_QIOT_ACTION_ID_BUTT) {
ble_qiot_log_e("invalid action id %d", action_id);
return -1;
}
return sg_ble_action_array[action_id].output_id_size;
}
int ble_action_user_handle_input_param(uint8_t action_id, e_ble_tlv *input_param_array, uint8_t input_array_size,
uint8_t *output_id_array)
{
if (action_id >= BLE_QIOT_ACTION_ID_BUTT) {
ble_qiot_log_e("invalid action id %d", action_id);
return -1;
}
if (NULL != sg_ble_action_array[action_id].input_cb) {
if (0 != sg_ble_action_array[action_id].input_cb(input_param_array, input_array_size, output_id_array)) {
ble_qiot_log_e("input handle error");
return -1;
}
}
return 0;
}
int ble_action_user_handle_output_param(uint8_t action_id, uint8_t output_id, char *buf, uint16_t buf_len)
{
int ret_len = 0;
if (action_id >= BLE_QIOT_ACTION_ID_BUTT) {
ble_qiot_log_e("invalid action id %d", action_id);
return -1;
}
if (NULL == sg_ble_action_array[action_id].output_cb) {
ble_qiot_log_e("invalid callback, action id %d", action_id);
return 0;
}
if (!ble_check_space_enough_by_type(sg_ble_action_array[action_id].output_type_array[output_id], buf_len)) {
ble_qiot_log_e("not enough space get data, action id %d, output id %d", action_id, output_id);
return -1;
}
ret_len = sg_ble_action_array[action_id].output_cb(output_id, buf, buf_len);
if (ret_len < 0) {
ble_qiot_log_e("get action data failed, action id %d, output id %d", action_id, output_id);
return -1;
} else {
if (ble_check_ret_value_by_type(sg_ble_action_array[action_id].output_type_array[output_id], buf_len,
ret_len)) {
return ret_len;
} else {
ble_qiot_log_e("action data length invalid, action id %d, output id %d", action_id, output_id);
return -1;
}
}
}
#ifdef __cplusplus
}
#endif

View File

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

View File

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

View File

@@ -0,0 +1,313 @@
/*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
* Licensed under the MIT License (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://opensource.org/licenses/MIT
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#ifdef __cplusplus
extern "C" {
#endif
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include "ble_qiot_export.h"
#include "ble_qiot_service.h"
#include "ble_qiot_import.h"
#include "nrf52832_xxaa_service.h"
// add std head file here
#include <stdint.h>
// add ble qiot head file here
#include "ble_qiot_import.h"
// add sdk head file here
#include "nordic_common.h"
#include "nrf.h"
#include "app_error.h"
#include "ble.h"
#include "ble_err.h"
#include "ble_gap.h"
#include "ble_hci.h"
#include "ble_srv_common.h"
#include "ble_advdata.h"
#include "ble_conn_params.h"
#include "nrf_sdh.h"
#include "nrf_sdh_ble.h"
#include "boards.h"
#include "app_timer.h"
#include "app_button.h"
#include "nrf_ble_gatt.h"
#include "nrf_ble_qwr.h"
#include "nrf_pwr_mgmt.h"
#include "nrf_delay.h"
#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"
#include "ble_qiot_config.h"
#include "flash_storage.h"
// divece info which defined in explorer platform
#define PRODUCT_ID "LR5NRSX9F5"
#define DEVICE_NAME "ble01"
#define SECRET_KEY "uG2TRl0hnCNsuLgls/65Bg=="
static uint8_t m_adv_handle =
BLE_GAP_ADV_SET_HANDLE_NOT_SET; /**< Advertising handle used to identify an advertising set. */
static uint8_t m_enc_advdata[BLE_GAP_ADV_SET_DATA_SIZE_MAX]; /**< Buffer for storing an encoded advertising set. */
static uint8_t m_enc_scan_response_data[BLE_GAP_ADV_SET_DATA_SIZE_MAX]; /**< Buffer for storing an encoded scan data. */
/**@brief Struct that contains pointers to the encoded advertising data. */
static ble_gap_adv_data_t m_adv_data = {
.adv_data = {.p_data = m_enc_advdata, .len = BLE_GAP_ADV_SET_DATA_SIZE_MAX},
.scan_rsp_data = {.p_data = m_enc_scan_response_data, .len = BLE_GAP_ADV_SET_DATA_SIZE_MAX
}};
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)
{
uint32_t err_code;
ble_gap_addr_t mac_info;
err_code = sd_ble_gap_addr_get(&mac_info);
if (NRF_SUCCESS != err_code) {
NRF_LOG_ERROR("Get MAC error, ret %d", err_code);
return err_code;
}
mac[0] = mac_info.addr[5];
mac[1] = mac_info.addr[4];
mac[2] = mac_info.addr[3];
mac[3] = mac_info.addr[2];
mac[4] = mac_info.addr[1];
mac[5] = mac_info.addr[0];
return 0;
}
int ble_write_flash(uint32_t flash_addr, const char *write_buf, uint16_t write_len)
{
return fstorage_write(flash_addr, write_len, write_buf);
}
int ble_read_flash(uint32_t flash_addr, char *read_buf, uint16_t read_len)
{
return fstorage_read(flash_addr, read_len, read_buf);
}
ble_qiot_ret_status_t ble_advertising_start(adv_info_s *adv)
{
ret_code_t err_code;
ble_gap_adv_params_t adv_params;
ble_advdata_t advdata;
// set Scan Response data, here set service uuid
ble_advdata_t srdata;
memset(&srdata, 0, sizeof(srdata));
ble_uuid_t adv_uuids[1];
adv_uuids[0].uuid = adv->uuid_info.uuids[0];
adv_uuids[0].type = BLE_UUID_TYPE_BLE;
srdata.uuids_complete.uuid_cnt = sizeof(adv_uuids) / sizeof(adv_uuids[0]);
srdata.uuids_complete.p_uuids = adv_uuids;
err_code = ble_advdata_encode(&srdata, m_adv_data.scan_rsp_data.p_data, &m_adv_data.scan_rsp_data.len);
APP_ERROR_CHECK(err_code);
// Build and set advertising data.
memset(&advdata, 0, sizeof(advdata));
advdata.name_type = BLE_ADVDATA_FULL_NAME;
advdata.flags = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE;
// set Advertising Data
ble_advdata_manuf_data_t manf_data;
memset(&manf_data, 0, sizeof(manf_data));
manf_data.company_identifier = adv->manufacturer_info.company_identifier;
manf_data.data.size = adv->manufacturer_info.adv_data_len;
manf_data.data.p_data = adv->manufacturer_info.adv_data;
advdata.p_manuf_specific_data = &manf_data;
err_code = ble_advdata_encode(&advdata, m_adv_data.adv_data.p_data, &m_adv_data.adv_data.len);
APP_ERROR_CHECK(err_code);
// Set advertising parameters.
memset(&adv_params, 0, sizeof(adv_params));
adv_params.primary_phy = BLE_GAP_PHY_1MBPS;
adv_params.duration = APP_ADV_DURATION;
adv_params.properties.type = BLE_GAP_ADV_TYPE_CONNECTABLE_SCANNABLE_UNDIRECTED;
adv_params.p_peer_addr = NULL;
adv_params.filter_policy = BLE_GAP_ADV_FP_ANY;
adv_params.interval = APP_ADV_INTERVAL;
err_code = sd_ble_gap_adv_set_configure(&m_adv_handle, &m_adv_data, &adv_params);
if (NRF_SUCCESS != err_code) {
NRF_LOG_ERROR("sd_ble_gap_adv_set_configure error, ret %d", err_code);
return BLE_QIOT_RS_ERR;
}
err_code = sd_ble_gap_adv_start(m_adv_handle, APP_BLE_CONN_CFG_TAG);
if (NRF_SUCCESS != err_code) {
NRF_LOG_ERROR("sd_ble_gap_adv_start error, ret %d", err_code);
return BLE_QIOT_RS_ERR;
}
return BLE_QIOT_RS_OK;
}
ble_qiot_ret_status_t ble_advertising_stop(void)
{
ret_code_t err_code;
err_code = sd_ble_gap_adv_stop(m_adv_handle);
if (NRF_SUCCESS != err_code) {
NRF_LOG_ERROR("sd_ble_gap_adv_stop error, ret %d", err_code);
return BLE_QIOT_RS_ERR;
}
return BLE_QIOT_RS_OK;
}
// define a static timer used in bind for example, a good way is used malloc
APP_TIMER_DEF(ble_bind_timer);
ble_timer_t ble_timer_create(uint8_t type, ble_timer_cb timeout_handle)
{
app_timer_create((app_timer_id_t const *)&ble_bind_timer,
type == BLE_TIMER_ONE_SHOT_TYPE ? APP_TIMER_MODE_SINGLE_SHOT : APP_TIMER_MODE_REPEATED,
(app_timer_timeout_handler_t)timeout_handle);
NRF_LOG_INFO("create timer id %p", (ble_timer_t)ble_bind_timer);
return (ble_timer_t)ble_bind_timer;
}
ble_qiot_ret_status_t ble_timer_start(ble_timer_t timer_id, uint32_t period)
{
ret_code_t ret = 0;
ret = app_timer_start((app_timer_id_t)timer_id, APP_TIMER_TICKS(period), NULL);
NRF_LOG_INFO("start timer id %p, tick %d, ret %d", timer_id, APP_TIMER_TICKS(period), ret);
return 0 == ret ? BLE_QIOT_RS_OK : BLE_QIOT_RS_ERR;
}
ble_qiot_ret_status_t ble_timer_stop(ble_timer_t timer_id)
{
ret_code_t ret = 0;
ret = app_timer_stop(timer_id);
NRF_LOG_INFO("stop timer id %p, ret %d", timer_id, ret);
return 0 == ret ? BLE_QIOT_RS_OK : BLE_QIOT_RS_ERR;
}
ble_qiot_ret_status_t ble_timer_delete(ble_timer_t timer_id)
{
// do nothing
return BLE_QIOT_RS_OK;
}
ble_qiot_ret_status_t ble_send_notify(uint8_t *buf, uint8_t len)
{
ret_code_t err_code;
ble_gatts_hvx_params_t params;
uint16_t data_len = len;
ble_priv_cfg_s * p_cfg;
p_cfg = ble_get_priv_cfg();
memset(&params, 0, sizeof(params));
params.type = BLE_GATT_HVX_NOTIFICATION;
params.handle = p_cfg->event_char_handle.value_handle; // handle, corresponds to the same characteristic
params.p_data = buf;
params.p_len = &data_len; // do not large than length set in characteristic
err_code = sd_ble_gatts_hvx(p_cfg->conn_handle, &params);
if (NRF_SUCCESS != err_code) {
NRF_LOG_ERROR("sd_ble_gatts_hvx error, ret %d", err_code);
return BLE_QIOT_RS_ERR;
}
return BLE_QIOT_RS_OK;
}
// should return ATT_MTU - 3
uint16_t ble_get_user_data_mtu_size(void)
{
ble_priv_cfg_s *p_cfg;
nrf_ble_gatt_t *p_gatt;
p_cfg = ble_get_priv_cfg();
p_gatt = ble_get_gatt_instance();
return nrf_ble_gatt_eff_mtu_get(p_gatt, p_cfg->conn_handle) - 3;
}
void property_power_switch(const char *data, uint16_t len)
{
if (data[0]) {
bsp_board_led_on(BSP_BOARD_LED_0);
NRF_LOG_INFO("Received LED ON!");
} else {
bsp_board_led_off(BSP_BOARD_LED_0);
NRF_LOG_INFO("Received LED OFF!");
}
return;
}
void action_led_blink(int ms)
{
bsp_board_led_on(BSP_BOARD_LED_1);
nrf_delay_ms(ms);
bsp_board_led_off(BSP_BOARD_LED_1);
nrf_delay_ms(ms);
bsp_board_led_on(BSP_BOARD_LED_1);
nrf_delay_ms(ms);
bsp_board_led_off(BSP_BOARD_LED_1);
nrf_delay_ms(ms);
bsp_board_led_on(BSP_BOARD_LED_1);
nrf_delay_ms(ms);
bsp_board_led_off(BSP_BOARD_LED_1);
}
void report_reply_blink(void)
{
bsp_board_led_on(BSP_BOARD_LED_2);
nrf_delay_ms(200);
bsp_board_led_off(BSP_BOARD_LED_2);
nrf_delay_ms(200);
bsp_board_led_on(BSP_BOARD_LED_2);
nrf_delay_ms(200);
bsp_board_led_off(BSP_BOARD_LED_2);
}
#ifdef __cplusplus
}
#endif

View File

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

View File

@@ -0,0 +1,84 @@
/*
* 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 1
#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__
// the following definition will affect the stack that LLSync usedthe minimum value tested is
// 2048BLE_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 (512)
// the minimum between BLE_QIOT_EVENT_MAX_SIZE and mtu
#define BLE_QIOT_EVENT_BUF_SIZE (256)
#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"
// in some BLE stack ble_qiot_log_hex() maybe not work, user can use there own hexdump function
#define BLE_QIOT_USER_DEFINE_HEDUMP 1
#if (1 == BLE_QIOT_USER_DEFINE_HEDUMP)
#define ble_qiot_log_hex(level, hex_name, data, data_len) \
do { \
NRF_LOG_INFO("\r\nble qiot dump: %s, length: %d\r\n", hex_name, data_len); \
NRF_LOG_RAW_HEXDUMP_INFO(data, data_len); \
} while (0)
#endif // BLE_QIOT_USER_DEFINE_HEDUMP
// Macro for logging a formatted string, the function must printf raw string without any color, prefix, newline or
// timestamp
#define BLE_QIOT_LOG_PRINT(...) NRF_LOG_RAW_INFO(__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
#define APP_BLE_OBSERVER_PRIO 3 /**< Application's BLE observer priority. You shouldn't need to modify this value. */
#define APP_BLE_CONN_CFG_TAG 1 /**< A tag identifying the SoftDevice BLE configuration. */
#define APP_ADV_INTERVAL 64 /**< The advertising interval (in units of 0.625 ms; this value corresponds to 40 ms). */
#define APP_ADV_DURATION \
BLE_GAP_ADV_TIMEOUT_GENERAL_UNLIMITED /**< The advertising time-out (in units of seconds). When set to 0, we will \
never time out. */
#ifdef __cplusplus
}
#endif
#endif // QCLOUD_BLE_QIOT_CONFIG_H

View File

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

View File

@@ -0,0 +1,48 @@
/*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
* Licensed under the MIT License (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://opensource.org/licenses/MIT
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include <stdint.h>
/**
* @brief initialize of flash storage
*
*/
void fstorage_init(void);
/**
* @brief read data from flash
*
* @param addr read address from flash
* @param read_len length of data to read
* @param p_data point to read buf
* @return read length is success, other is error
*/
int fstorage_read(uint32_t addr, uint32_t read_len, void *p_data);
/**
* @brief write data to flash, must erase before write
*
* @param addr write address in flash
* @param write_len length of data to write
* @param p_data point to write buf
* @return write length is success, other is error
*/
int fstorage_write(uint32_t addr, uint32_t write_len, void const *p_data);
/**
* @brief erase one page
*
* @param addr address must align to page. For example, one page is 4096 bytes,
* you want to erase address 0x1020, you should set address 0x1000
* @return 0 is succcess, other is error
*/
int fstorage_erase(uint32_t addr);

View File

@@ -0,0 +1,333 @@
/*
* 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 <string.h>
#include "nordic_common.h"
#include "nrf.h"
#include "app_error.h"
#include "ble.h"
#include "ble_err.h"
#include "ble_hci.h"
#include "ble_srv_common.h"
#include "ble_advdata.h"
#include "ble_conn_params.h"
#include "nrf_sdh.h"
#include "nrf_sdh_ble.h"
#include "boards.h"
#include "app_timer.h"
#include "app_button.h"
#include "nrf_ble_gatt.h"
#include "nrf_ble_qwr.h"
#include "nrf_pwr_mgmt.h"
#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"
#include "ble_qiot_service.h"
#include "ble_qiot_import.h"
BLE_PRIV_DEF(priv_cfg);
NRF_BLE_GATT_DEF(m_gatt); /**< GATT module instance. */
#define ATTRIBUTE_VALUE_MAX_LEN 256
ble_priv_cfg_s *ble_get_priv_cfg(void)
{
return &priv_cfg;
}
nrf_ble_gatt_t *ble_get_gatt_instance(void)
{
return &m_gatt;
}
// on_write event
static void on_write(ble_priv_cfg_s *p_cfg, ble_evt_t const *p_ble_evt)
{
ble_gatts_evt_write_t const *p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
// print raw data for debug
NRF_LOG_INFO("dump write data, len %d", p_evt_write->len);
NRF_LOG_RAW_HEXDUMP_INFO(p_evt_write->data, p_evt_write->len);
if ((p_evt_write->handle == p_cfg->device_info_char_handle.value_handle) &&
(p_cfg->iot_device_info_write_handler != NULL)) {
p_cfg->iot_device_info_write_handler(p_evt_write->data, p_evt_write->len);
} else if ((p_evt_write->handle == p_cfg->data_char_handle.value_handle) &&
(p_cfg->iot_data_write_handler != NULL)) {
p_cfg->iot_data_write_handler(p_evt_write->data, p_evt_write->len);
}
}
void iot_on_ble_evt(ble_evt_t const *p_ble_evt, void *p_context)
{
ret_code_t err_code;
ble_priv_cfg_s *p_cfg = (ble_priv_cfg_s *)p_context;
NRF_LOG_INFO("evt_id %d", p_ble_evt->header.evt_id);
switch (p_ble_evt->header.evt_id) {
case BLE_GAP_EVT_CONNECTED:
// on_connect(p_hrs, p_ble_evt);
NRF_LOG_INFO("Connected");
p_cfg->conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
ble_gap_connect_cb();
break;
case BLE_GAP_EVT_DISCONNECTED:
// on_disconnect(p_hrs, p_ble_evt);
NRF_LOG_INFO("Disconnected");
p_cfg->conn_handle = BLE_CONN_HANDLE_INVALID;
ble_gap_disconnect_cb();
break;
case BLE_GATTS_EVT_WRITE:
on_write(p_cfg, p_ble_evt);
break;
case BLE_GATTS_EVT_SYS_ATTR_MISSING:
// No system attributes have been stored.
err_code = sd_ble_gatts_sys_attr_set(p_cfg->conn_handle, NULL, 0, 0);
APP_ERROR_CHECK(err_code);
// NRF_LOG_INFO("err_code %d", err_code);
break;
case BLE_GATTS_EVT_HVC:
NRF_LOG_INFO("indication response %d", p_ble_evt->evt.gatts_evt.params.hvn_tx_complete.count);
break;
#if defined(S132)
case BLE_GAP_EVT_PHY_UPDATE_REQUEST: {
NRF_LOG_DEBUG("PHY update request.");
ble_gap_phys_t const phys = {
.rx_phys = BLE_GAP_PHY_AUTO,
.tx_phys = BLE_GAP_PHY_AUTO,
};
err_code = sd_ble_gap_phy_update(p_ble_evt->evt.gap_evt.conn_handle, &phys);
APP_ERROR_CHECK(err_code);
} break;
#endif
default:
// No implementation needed.
break;
}
}
// add services and characteristic
void ble_services_add(const qiot_service_init_s *p_service)
{
ret_code_t err_code;
ble_uuid_t service_uuid;
ble_uuid128_t ble_uuid128;
ble_gatts_char_md_t char_md;
ble_gatts_attr_t attr_char_value;
ble_uuid_t char_uuid;
ble_gatts_attr_md_t attr_md;
ble_gatts_attr_md_t user_descr_attr_md;
ble_gatts_attr_md_t cccd_md;
ble_priv_cfg_s *p_cfg;
p_cfg = ble_get_priv_cfg();
/*************************************************************************/
// if it's necessary to save those configuration in private configuration
p_cfg->iot_device_info_write_handler = p_service->device_info.on_write;
p_cfg->iot_data_write_handler = p_service->data.on_write;
/*************************************************************************/
// add service
// set uuid128 to ble stack, return uuid type
memcpy(ble_uuid128.uuid128, p_service->service_uuid128, sizeof(ble_uuid128.uuid128));
err_code = sd_ble_uuid_vs_add(&ble_uuid128, &p_cfg->uuid_type);
// set service uuid
service_uuid.type = p_cfg->uuid_type;
service_uuid.uuid = IOT_BLE_UUID_SERVICE;
err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY, &service_uuid, &p_cfg->service_handle);
if (err_code != NRF_SUCCESS) {
NRF_LOG_ERROR("err at file %s, line %d, err_code %d \n", __FILE__, __LINE__, err_code);
return;
}
/*************************************************************************/
// set device info characteristic, uuid 0xFEE1
memset(&char_md, 0, sizeof(char_md));
memset(&attr_char_value, 0, sizeof(attr_char_value));
memset(&char_uuid, 0, sizeof(char_uuid));
memset(&attr_md, 0, sizeof(attr_md));
memset(&user_descr_attr_md, 0, sizeof(user_descr_attr_md));
memset(&cccd_md, 0, sizeof(cccd_md));
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm);
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.write_perm);
// BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&cccd_md.write_perm);
cccd_md.rd_auth = 0;
cccd_md.wr_auth = 0;
cccd_md.vlen = 1;
cccd_md.vloc = BLE_GATTS_VLOC_STACK;
char_md.char_props.broadcast = ((p_service->device_info.gatt_char_props & GATT_CHAR_BROADCAST) ? 1 : 0);
char_md.char_props.read = ((p_service->device_info.gatt_char_props & GATT_CHAR_READ) ? 1 : 0);
char_md.char_props.write_wo_resp = ((p_service->device_info.gatt_char_props & GATT_CHAR_WRITE_WO_RESP) ? 1 : 0);
char_md.char_props.write = ((p_service->device_info.gatt_char_props & GATT_CHAR_WRITE) ? 1 : 0);
char_md.char_props.notify = ((p_service->device_info.gatt_char_props & GATT_CHAR_NOTIFY) ? 1 : 0);
char_md.char_props.indicate = ((p_service->device_info.gatt_char_props & GATT_CHAR_INDICATE) ? 1 : 0);
char_md.char_props.auth_signed_wr = ((p_service->device_info.gatt_char_props & GATT_CHAR_AUTH_SIGNED_WR) ? 1 : 0);
char_md.p_char_pf = NULL;
char_md.p_user_desc_md = NULL;
char_md.p_cccd_md = &cccd_md;
char_md.p_sccd_md = NULL;
char_uuid.type = p_cfg->uuid_type;
char_uuid.uuid = p_service->device_info.uuid16;
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm);
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.write_perm);
attr_md.vloc = BLE_GATTS_VLOC_STACK;
attr_md.rd_auth = 0;
attr_md.wr_auth = 0;
attr_md.vlen = 1;
attr_char_value.p_uuid = &char_uuid;
attr_char_value.p_attr_md = &attr_md;
attr_char_value.init_len = sizeof(uint8_t);
attr_char_value.init_offs = 0;
attr_char_value.max_len = sizeof(uint8_t) * ATTRIBUTE_VALUE_MAX_LEN;
attr_char_value.p_value = NULL;
err_code = sd_ble_gatts_characteristic_add(p_cfg->service_handle, &char_md, &attr_char_value,
&p_cfg->device_info_char_handle);
if (err_code != NRF_SUCCESS) {
NRF_LOG_ERROR("err at file %s, line %d, err_code %d \n", __FILE__, __LINE__, err_code);
return;
}
/*************************************************************************/
// set data characteristic, uuid 0xFEE2
memset(&char_md, 0, sizeof(char_md));
memset(&attr_char_value, 0, sizeof(attr_char_value));
memset(&char_uuid, 0, sizeof(char_uuid));
memset(&attr_md, 0, sizeof(attr_md));
memset(&user_descr_attr_md, 0, sizeof(user_descr_attr_md));
memset(&cccd_md, 0, sizeof(cccd_md));
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm);
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.write_perm);
// BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&cccd_md.write_perm);
cccd_md.rd_auth = 0;
cccd_md.wr_auth = 0;
cccd_md.vlen = 1;
cccd_md.vloc = BLE_GATTS_VLOC_STACK;
char_md.char_props.broadcast = ((p_service->data.gatt_char_props & GATT_CHAR_BROADCAST) ? 1 : 0);
char_md.char_props.read = ((p_service->data.gatt_char_props & GATT_CHAR_READ) ? 1 : 0);
char_md.char_props.write_wo_resp = ((p_service->data.gatt_char_props & GATT_CHAR_WRITE_WO_RESP) ? 1 : 0);
char_md.char_props.write = ((p_service->data.gatt_char_props & GATT_CHAR_WRITE) ? 1 : 0);
char_md.char_props.notify = ((p_service->data.gatt_char_props & GATT_CHAR_NOTIFY) ? 1 : 0);
char_md.char_props.indicate = ((p_service->data.gatt_char_props & GATT_CHAR_INDICATE) ? 1 : 0);
char_md.char_props.auth_signed_wr = ((p_service->data.gatt_char_props & GATT_CHAR_AUTH_SIGNED_WR) ? 1 : 0);
char_md.p_char_pf = NULL;
char_md.p_user_desc_md = NULL;
char_md.p_cccd_md = &cccd_md;
char_md.p_sccd_md = NULL;
char_uuid.type = p_cfg->uuid_type;
char_uuid.uuid = p_service->data.uuid16;
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm);
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.write_perm);
attr_md.vloc = BLE_GATTS_VLOC_STACK;
attr_md.rd_auth = 0;
attr_md.wr_auth = 0;
attr_md.vlen = 1;
attr_char_value.p_uuid = &char_uuid;
attr_char_value.p_attr_md = &attr_md;
attr_char_value.init_len = sizeof(uint8_t);
attr_char_value.init_offs = 0;
attr_char_value.max_len = sizeof(uint8_t) * ATTRIBUTE_VALUE_MAX_LEN;
attr_char_value.p_value = NULL;
err_code =
sd_ble_gatts_characteristic_add(p_cfg->service_handle, &char_md, &attr_char_value, &p_cfg->data_char_handle);
if (err_code != NRF_SUCCESS) {
NRF_LOG_ERROR("err at file %s, line %d, err_code %d \n", __FILE__, __LINE__, err_code);
return;
}
/*************************************************************************/
// set event characteristic, uuid 0xFEE3
memset(&char_md, 0, sizeof(char_md));
memset(&attr_char_value, 0, sizeof(attr_char_value));
memset(&char_uuid, 0, sizeof(char_uuid));
memset(&attr_md, 0, sizeof(attr_md));
memset(&user_descr_attr_md, 0, sizeof(user_descr_attr_md));
memset(&cccd_md, 0, sizeof(cccd_md));
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm);
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.write_perm);
// BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&cccd_md.write_perm);
cccd_md.rd_auth = 0;
cccd_md.wr_auth = 0;
cccd_md.vlen = 1;
cccd_md.vloc = BLE_GATTS_VLOC_STACK;
char_md.char_props.broadcast = ((p_service->event.gatt_char_props & GATT_CHAR_BROADCAST) ? 1 : 0);
char_md.char_props.read = ((p_service->event.gatt_char_props & GATT_CHAR_READ) ? 1 : 0);
char_md.char_props.write_wo_resp = ((p_service->event.gatt_char_props & GATT_CHAR_WRITE_WO_RESP) ? 1 : 0);
char_md.char_props.write = ((p_service->event.gatt_char_props & GATT_CHAR_WRITE) ? 1 : 0);
char_md.char_props.notify = ((p_service->event.gatt_char_props & GATT_CHAR_NOTIFY) ? 1 : 0);
char_md.char_props.indicate = ((p_service->event.gatt_char_props & GATT_CHAR_INDICATE) ? 1 : 0);
char_md.char_props.auth_signed_wr = ((p_service->event.gatt_char_props & GATT_CHAR_AUTH_SIGNED_WR) ? 1 : 0);
char_md.p_char_pf = NULL;
char_md.p_user_desc_md = NULL;
char_md.p_cccd_md = &cccd_md;
char_md.p_sccd_md = NULL;
char_uuid.type = p_cfg->uuid_type;
char_uuid.uuid = p_service->event.uuid16;
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm);
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.write_perm);
attr_md.vloc = BLE_GATTS_VLOC_STACK;
attr_md.rd_auth = 0;
attr_md.wr_auth = 0;
attr_md.vlen = 1;
attr_char_value.p_uuid = &char_uuid;
attr_char_value.p_attr_md = &attr_md;
// attr_char_value.init_len = sizeof(uint8_t);
attr_char_value.init_len = sizeof(uint8_t) * 10;
attr_char_value.init_offs = 0;
attr_char_value.max_len = sizeof(uint8_t) * ATTRIBUTE_VALUE_MAX_LEN;
attr_char_value.p_value = "hello";
err_code =
sd_ble_gatts_characteristic_add(p_cfg->service_handle, &char_md, &attr_char_value, &p_cfg->event_char_handle);
if (err_code != NRF_SUCCESS) {
NRF_LOG_ERROR("err at file %s, line %d, err_code %d \n", __FILE__, __LINE__, err_code);
return;
}
}

View File

@@ -0,0 +1,62 @@
/*
* 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 __NRF52832_XXAA_SERVICE_H
#define __NRF52832_XXAA_SERVICE_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stdbool.h>
#include "ble.h"
#include "ble_srv_common.h"
#include "ble_qiot_export.h"
#include "nrf_sdh_ble.h"
#include "nrf_ble_gatt.h"
#define BLE_PRIV_DEF(_name) \
static ble_priv_cfg_s _name; \
NRF_SDH_BLE_OBSERVER(_name##_obs, BLE_LBS_BLE_OBSERVER_PRIO, iot_on_ble_evt, &_name)
typedef struct _ble_priv_cfg_s ble_priv_cfg_s;
typedef void (*indi_resp_cb)(uint8_t res);
// save BLE service configuration, such as handle, callback function, and so on, you can edit it as your requirements
struct _ble_priv_cfg_s {
uint16_t service_handle;
uint8_t uuid_type; // UUID type for the service.
ble_gatts_char_handles_t device_info_char_handle;
ble_gatts_char_handles_t data_char_handle;
ble_gatts_char_handles_t event_char_handle;
// characteristic write callback function
ble_on_write_cb iot_device_info_write_handler;
ble_on_write_cb iot_data_write_handler;
uint16_t conn_handle; /**< Handle of the current connection (as provided by the BLE stack, is
BLE_CONN_HANDLE_INVALID if not in a connection). */
};
ble_priv_cfg_s *ble_get_priv_cfg(void);
nrf_ble_gatt_t *ble_get_gatt_instance(void);
void iot_on_ble_evt(ble_evt_t const *p_ble_evt, void *p_context);
void ble_services_add(const qiot_service_init_s *p_service);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,425 @@
/*
* 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>
#include <string.h>
#include "nordic_common.h"
#include "nrf.h"
#include "app_error.h"
#include "ble.h"
#include "ble_err.h"
#include "ble_hci.h"
#include "ble_srv_common.h"
#include "ble_advdata.h"
#include "ble_conn_params.h"
#include "nrf_sdh.h"
#include "nrf_sdh_ble.h"
#include "boards.h"
#include "app_timer.h"
#include "app_button.h"
#include "nrf_ble_gatt.h"
#include "nrf_ble_qwr.h"
#include "nrf_pwr_mgmt.h"
#include "nrf_delay.h"
#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"
#include "nrf52832_xxaa_service.h"
#include "ble_qiot_llsync_device.h"
#include "ble_qiot_service.h"
#include "ble_qiot_import.h"
#include "ble_qiot_config.h"
#include "flash_storage.h"
#define USER_BUTTON_BUTTON1 \
BSP_BUTTON_0 /**< Button that will trigger the notification event with the LED Button Service */
#define USER_BUTTON_BUTTON2 \
BSP_BUTTON_1 /**< Button that will trigger the notification event with the LED Button Service */
#define USER_BUTTON_BUTTON3 \
BSP_BUTTON_2 /**< Button that will trigger the notification event with the LED Button Service */
#define USER_BUTTON_BUTTON4 \
BSP_BUTTON_3 /**< Button that will trigger the notification event with the LED Button Service */
#define GAP_DEVICE_NAME "IoT"
#define MIN_CONN_INTERVAL MSEC_TO_UNITS(100, UNIT_1_25_MS) /**< Minimum acceptable connection interval (0.5 seconds). \
*/
#define MAX_CONN_INTERVAL MSEC_TO_UNITS(200, UNIT_1_25_MS) /**< Maximum acceptable connection interval (1 second). */
#define SLAVE_LATENCY 0 /**< Slave latency. */
#define CONN_SUP_TIMEOUT MSEC_TO_UNITS(4000, UNIT_10_MS) /**< Connection supervisory time-out (4 seconds). */
#define FIRST_CONN_PARAMS_UPDATE_DELAY \
APP_TIMER_TICKS(20000) /**< Time from initiating event (connect or start of notification) to first time \
sd_ble_gap_conn_param_update is called (15 seconds). */
#define NEXT_CONN_PARAMS_UPDATE_DELAY \
APP_TIMER_TICKS( \
5000) /**< Time between each call to sd_ble_gap_conn_param_update after the first call (5 seconds). */
#define MAX_CONN_PARAMS_UPDATE_COUNT 3 /**< Number of attempts before giving up the connection parameter negotiation. \
*/
#define BUTTON_DETECTION_DELAY \
APP_TIMER_TICKS( \
50) /**< Delay from a GPIOTE event until a button is reported as pushed (in number of timer ticks). */
#define DEAD_BEEF \
0xDEADBEEF /**< Value used as error code on stack dump, can be used to identify stack location on stack unwind. */
NRF_BLE_QWR_DEF(m_qwr); /**< Context for the Queued Write module.*/
/**@brief Function for assert macro callback.
*
* @details This function will be called in case of an assert in the SoftDevice.
*
* @warning This handler is an example only and does not fit a final product. You need to analyze
* how your product is supposed to react in case of Assert.
* @warning On assert from the SoftDevice, the system can only recover on reset.
*
* @param[in] line_num Line number of the failing ASSERT call.
* @param[in] p_file_name File name of the failing ASSERT call.
*/
void assert_nrf_callback(uint16_t line_num, const uint8_t *p_file_name)
{
app_error_handler(DEAD_BEEF, line_num, p_file_name);
}
/**@brief Function for the LEDs initialization.
*
* @details Initializes all LEDs used by the application.
*/
static void leds_init(void)
{
bsp_board_init(BSP_INIT_LEDS);
}
/**@brief Function for the Timer initialization.
*
* @details Initializes the timer module.
*/
static void timers_init(void)
{
// Initialize timer module, making it use the scheduler
ret_code_t err_code = app_timer_init();
APP_ERROR_CHECK(err_code);
}
/**@brief Function for the GAP initialization.
*
* @details This function sets up all the necessary GAP (Generic Access Profile) parameters of the
* device including the device name, appearance, and the preferred connection parameters.
*/
static void gap_params_init(void)
{
ret_code_t err_code;
ble_gap_conn_params_t gap_conn_params;
ble_gap_conn_sec_mode_t sec_mode;
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode);
err_code = sd_ble_gap_device_name_set(&sec_mode, (const uint8_t *)GAP_DEVICE_NAME, strlen(GAP_DEVICE_NAME));
APP_ERROR_CHECK(err_code);
memset(&gap_conn_params, 0, sizeof(gap_conn_params));
gap_conn_params.min_conn_interval = MIN_CONN_INTERVAL;
gap_conn_params.max_conn_interval = MAX_CONN_INTERVAL;
gap_conn_params.slave_latency = SLAVE_LATENCY;
gap_conn_params.conn_sup_timeout = CONN_SUP_TIMEOUT;
err_code = sd_ble_gap_ppcp_set(&gap_conn_params);
APP_ERROR_CHECK(err_code);
}
/**@brief Function for initializing the GATT module.
*/
static void gatt_init(void)
{
nrf_ble_gatt_t *p_gatt;
p_gatt = ble_get_gatt_instance();
ret_code_t err_code = nrf_ble_gatt_init(p_gatt, NULL);
APP_ERROR_CHECK(err_code);
}
/**@brief Function for handling Queued Write Module errors.
*
* @details A pointer to this function will be passed to each service which may need to inform the
* application about an error.
*
* @param[in] nrf_error Error code containing information about what went wrong.
*/
static void nrf_qwr_error_handler(uint32_t nrf_error)
{
APP_ERROR_HANDLER(nrf_error);
}
/**@brief Function for initializing services that will be used by the application.
*/
static void services_init(void)
{
ret_code_t err_code;
// ble_lbs_init_t init = {0};
nrf_ble_qwr_init_t qwr_init = {0};
// Initialize Queued Write Module.
qwr_init.error_handler = nrf_qwr_error_handler;
err_code = nrf_ble_qwr_init(&m_qwr, &qwr_init);
APP_ERROR_CHECK(err_code);
}
/**@brief Function for handling the Connection Parameters Module.
*
* @details This function will be called for all events in the Connection Parameters Module that
* are passed to the application.
*
* @note All this function does is to disconnect. This could have been done by simply
* setting the disconnect_on_fail config parameter, but instead we use the event
* handler mechanism to demonstrate its use.
*
* @param[in] p_evt Event received from the Connection Parameters Module.
*/
static void on_conn_params_evt(ble_conn_params_evt_t *p_evt)
{
ret_code_t err_code;
ble_priv_cfg_s *p_cfg;
p_cfg = ble_get_priv_cfg();
if (p_evt->evt_type == BLE_CONN_PARAMS_EVT_FAILED) {
err_code = sd_ble_gap_disconnect(p_cfg->conn_handle, BLE_HCI_CONN_INTERVAL_UNACCEPTABLE);
APP_ERROR_CHECK(err_code);
}
}
/**@brief Function for handling a Connection Parameters error.
*
* @param[in] nrf_error Error code containing information about what went wrong.
*/
static void conn_params_error_handler(uint32_t nrf_error)
{
APP_ERROR_HANDLER(nrf_error);
}
/**@brief Function for initializing the Connection Parameters module.
*/
static void conn_params_init(void)
{
ret_code_t err_code;
ble_conn_params_init_t cp_init;
memset(&cp_init, 0, sizeof(cp_init));
cp_init.p_conn_params = NULL;
cp_init.first_conn_params_update_delay = FIRST_CONN_PARAMS_UPDATE_DELAY;
cp_init.next_conn_params_update_delay = NEXT_CONN_PARAMS_UPDATE_DELAY;
cp_init.max_conn_params_update_count = MAX_CONN_PARAMS_UPDATE_COUNT;
cp_init.start_on_notify_cccd_handle = BLE_GATT_HANDLE_INVALID;
cp_init.disconnect_on_fail = false;
cp_init.evt_handler = on_conn_params_evt;
cp_init.error_handler = conn_params_error_handler;
err_code = ble_conn_params_init(&cp_init);
APP_ERROR_CHECK(err_code);
}
/**@brief Function for initializing the BLE stack.
*
* @details Initializes the SoftDevice and the BLE event interrupt.
*/
static void ble_stack_init(void)
{
ret_code_t err_code;
err_code = nrf_sdh_enable_request();
APP_ERROR_CHECK(err_code);
// Configure the BLE stack using the default settings.
// Fetch the start address of the application RAM.
uint32_t ram_start = 0;
err_code = nrf_sdh_ble_default_cfg_set(APP_BLE_CONN_CFG_TAG, &ram_start);
APP_ERROR_CHECK(err_code);
// Enable BLE stack.
err_code = nrf_sdh_ble_enable(&ram_start);
APP_ERROR_CHECK(err_code);
}
void ble_iot_button1_change(uint8_t button_action)
{
static uint8_t last_button_action = 0;
if (last_button_action == 1 && button_action == 0) {
ble_qiot_advertising_start();
}
last_button_action = button_action;
}
void ble_iot_button2_change(uint8_t button_action)
{
static uint8_t last_button_action = 0;
static int button2_index = 0;
if (last_button_action == 1 && button_action == 0) {
NRF_LOG_INFO("event id %d", button2_index % 3);
ble_event_post(button2_index % 3);
button2_index++;
}
last_button_action = button_action;
}
void ble_iot_button3_change(uint8_t button_action)
{
static uint8_t last_button_action = 0;
if (last_button_action == 1 && button_action == 0) {
NRF_LOG_INFO("erase flash at addr 0x%X", BLE_QIOT_RECORD_FLASH_ADDR);
fstorage_erase(BLE_QIOT_RECORD_FLASH_ADDR);
}
last_button_action = button_action;
}
void ble_iot_button4_change(uint8_t button_action)
{
static uint8_t last_button_action = 0;
static int button4_index = 1;
if (last_button_action == 1 && button_action == 0) {
if (button4_index % 2 == 0) {
NRF_LOG_INFO("get status");
ble_event_get_status();
} else {
NRF_LOG_INFO("report property");
ble_event_report_property();
}
button4_index++;
}
last_button_action = button_action;
}
/**@brief Function for handling events from the button handler module.
*
* @param[in] pin_no The pin that the event applies to.
* @param[in] button_action The button action (press/release).
*/
static void button_event_handler(uint8_t pin_no, uint8_t button_action)
{
// ret_code_t err_code;
NRF_LOG_INFO("button --> %d %d", pin_no, button_action);
switch (pin_no) {
case USER_BUTTON_BUTTON1:
ble_iot_button1_change(button_action);
break;
case USER_BUTTON_BUTTON2:
ble_iot_button2_change(button_action);
break;
case USER_BUTTON_BUTTON3:
ble_iot_button3_change(button_action);
break;
case USER_BUTTON_BUTTON4:
ble_iot_button4_change(button_action);
break;
default:
APP_ERROR_HANDLER(pin_no);
break;
}
}
/**@brief Function for initializing the button handler module.
*/
static void buttons_init(void)
{
ret_code_t err_code;
// The array must be static because a pointer to it will be saved in the button handler module.
static app_button_cfg_t buttons[] = {
{USER_BUTTON_BUTTON1, false, BUTTON_PULL, button_event_handler},
{USER_BUTTON_BUTTON2, false, BUTTON_PULL, button_event_handler},
{USER_BUTTON_BUTTON3, false, BUTTON_PULL, button_event_handler},
{USER_BUTTON_BUTTON4, false, BUTTON_PULL, button_event_handler},
};
err_code = app_button_init(buttons, ARRAY_SIZE(buttons), BUTTON_DETECTION_DELAY);
APP_ERROR_CHECK(err_code);
err_code = app_button_enable();
APP_ERROR_CHECK(err_code);
}
static void log_init(void)
{
ret_code_t err_code = NRF_LOG_INIT(NULL);
APP_ERROR_CHECK(err_code);
NRF_LOG_DEFAULT_BACKENDS_INIT();
}
/**@brief Function for initializing power management.
*/
static void power_management_init(void)
{
ret_code_t err_code;
err_code = nrf_pwr_mgmt_init();
APP_ERROR_CHECK(err_code);
}
/**@brief Function for handling the idle state (main loop).
*
* @details If there is no pending log operation, then sleep until next the next event occurs.
*/
static void idle_state_handle(void)
{
if (NRF_LOG_PROCESS() == false) {
nrf_pwr_mgmt_run();
}
}
/**@brief Function for application main entry.
*/
int main(void)
{
// Initialize.
log_init();
leds_init();
timers_init();
buttons_init();
power_management_init();
ble_stack_init();
gap_params_init();
gatt_init();
services_init();
fstorage_init();
ble_qiot_explorer_init();
#if (1 == BLE_QIOT_BUTTON_BROADCAST)
if (E_LLSYNC_BIND_SUCC == llsync_bind_state_get())
#endif
{
ble_qiot_advertising_start();
}
conn_params_init();
// Start execution.
NRF_LOG_INFO("Blinky example started.");
// Enter main loop.
for (;;) {
idle_state_handle();
}
}

View File

@@ -0,0 +1,371 @@
; Copyright (c) 2009-2018 ARM Limited. All rights reserved.
;
; SPDX-License-Identifier: Apache-2.0
;
; Licensed 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
;
; 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.
;
; NOTICE: This file has been modified by Nordic Semiconductor ASA.
IF :DEF: __STARTUP_CONFIG
#ifdef __STARTUP_CONFIG
#include "startup_config.h"
#ifndef __STARTUP_CONFIG_STACK_ALIGNEMENT
#define __STARTUP_CONFIG_STACK_ALIGNEMENT 3
#endif
#endif
ENDIF
IF :DEF: __STARTUP_CONFIG
Stack_Size EQU __STARTUP_CONFIG_STACK_SIZE
ELIF :DEF: __STACK_SIZE
Stack_Size EQU __STACK_SIZE
ELSE
Stack_Size EQU 8192
ENDIF
IF :DEF: __STARTUP_CONFIG
Stack_Align EQU __STARTUP_CONFIG_STACK_ALIGNEMENT
ELSE
Stack_Align EQU 3
ENDIF
AREA STACK, NOINIT, READWRITE, ALIGN=Stack_Align
Stack_Mem SPACE Stack_Size
__initial_sp
IF :DEF: __STARTUP_CONFIG
Heap_Size EQU __STARTUP_CONFIG_HEAP_SIZE
ELIF :DEF: __HEAP_SIZE
Heap_Size EQU __HEAP_SIZE
ELSE
Heap_Size EQU 8192
ENDIF
AREA HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base
Heap_Mem SPACE Heap_Size
__heap_limit
PRESERVE8
THUMB
; Vector Table Mapped to Address 0 at Reset
AREA RESET, DATA, READONLY
EXPORT __Vectors
EXPORT __Vectors_End
EXPORT __Vectors_Size
__Vectors DCD __initial_sp ; Top of Stack
DCD Reset_Handler
DCD NMI_Handler
DCD HardFault_Handler
DCD MemoryManagement_Handler
DCD BusFault_Handler
DCD UsageFault_Handler
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD SVC_Handler
DCD DebugMon_Handler
DCD 0 ; Reserved
DCD PendSV_Handler
DCD SysTick_Handler
; External Interrupts
DCD POWER_CLOCK_IRQHandler
DCD RADIO_IRQHandler
DCD UARTE0_UART0_IRQHandler
DCD SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQHandler
DCD SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1_IRQHandler
DCD NFCT_IRQHandler
DCD GPIOTE_IRQHandler
DCD SAADC_IRQHandler
DCD TIMER0_IRQHandler
DCD TIMER1_IRQHandler
DCD TIMER2_IRQHandler
DCD RTC0_IRQHandler
DCD TEMP_IRQHandler
DCD RNG_IRQHandler
DCD ECB_IRQHandler
DCD CCM_AAR_IRQHandler
DCD WDT_IRQHandler
DCD RTC1_IRQHandler
DCD QDEC_IRQHandler
DCD COMP_LPCOMP_IRQHandler
DCD SWI0_EGU0_IRQHandler
DCD SWI1_EGU1_IRQHandler
DCD SWI2_EGU2_IRQHandler
DCD SWI3_EGU3_IRQHandler
DCD SWI4_EGU4_IRQHandler
DCD SWI5_EGU5_IRQHandler
DCD TIMER3_IRQHandler
DCD TIMER4_IRQHandler
DCD PWM0_IRQHandler
DCD PDM_IRQHandler
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD MWU_IRQHandler
DCD PWM1_IRQHandler
DCD PWM2_IRQHandler
DCD SPIM2_SPIS2_SPI2_IRQHandler
DCD RTC2_IRQHandler
DCD I2S_IRQHandler
DCD FPU_IRQHandler
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
__Vectors_End
__Vectors_Size EQU __Vectors_End - __Vectors
AREA |.text|, CODE, READONLY
; Reset Handler
Reset_Handler PROC
EXPORT Reset_Handler [WEAK]
IMPORT SystemInit
IMPORT __main
LDR R0, =SystemInit
BLX R0
LDR R0, =__main
BX R0
ENDP
; Dummy Exception Handlers (infinite loops which can be modified)
NMI_Handler PROC
EXPORT NMI_Handler [WEAK]
B .
ENDP
HardFault_Handler\
PROC
EXPORT HardFault_Handler [WEAK]
B .
ENDP
MemoryManagement_Handler\
PROC
EXPORT MemoryManagement_Handler [WEAK]
B .
ENDP
BusFault_Handler\
PROC
EXPORT BusFault_Handler [WEAK]
B .
ENDP
UsageFault_Handler\
PROC
EXPORT UsageFault_Handler [WEAK]
B .
ENDP
SVC_Handler PROC
EXPORT SVC_Handler [WEAK]
B .
ENDP
DebugMon_Handler\
PROC
EXPORT DebugMon_Handler [WEAK]
B .
ENDP
PendSV_Handler PROC
EXPORT PendSV_Handler [WEAK]
B .
ENDP
SysTick_Handler PROC
EXPORT SysTick_Handler [WEAK]
B .
ENDP
Default_Handler PROC
EXPORT POWER_CLOCK_IRQHandler [WEAK]
EXPORT RADIO_IRQHandler [WEAK]
EXPORT UARTE0_UART0_IRQHandler [WEAK]
EXPORT SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQHandler [WEAK]
EXPORT SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1_IRQHandler [WEAK]
EXPORT NFCT_IRQHandler [WEAK]
EXPORT GPIOTE_IRQHandler [WEAK]
EXPORT SAADC_IRQHandler [WEAK]
EXPORT TIMER0_IRQHandler [WEAK]
EXPORT TIMER1_IRQHandler [WEAK]
EXPORT TIMER2_IRQHandler [WEAK]
EXPORT RTC0_IRQHandler [WEAK]
EXPORT TEMP_IRQHandler [WEAK]
EXPORT RNG_IRQHandler [WEAK]
EXPORT ECB_IRQHandler [WEAK]
EXPORT CCM_AAR_IRQHandler [WEAK]
EXPORT WDT_IRQHandler [WEAK]
EXPORT RTC1_IRQHandler [WEAK]
EXPORT QDEC_IRQHandler [WEAK]
EXPORT COMP_LPCOMP_IRQHandler [WEAK]
EXPORT SWI0_EGU0_IRQHandler [WEAK]
EXPORT SWI1_EGU1_IRQHandler [WEAK]
EXPORT SWI2_EGU2_IRQHandler [WEAK]
EXPORT SWI3_EGU3_IRQHandler [WEAK]
EXPORT SWI4_EGU4_IRQHandler [WEAK]
EXPORT SWI5_EGU5_IRQHandler [WEAK]
EXPORT TIMER3_IRQHandler [WEAK]
EXPORT TIMER4_IRQHandler [WEAK]
EXPORT PWM0_IRQHandler [WEAK]
EXPORT PDM_IRQHandler [WEAK]
EXPORT MWU_IRQHandler [WEAK]
EXPORT PWM1_IRQHandler [WEAK]
EXPORT PWM2_IRQHandler [WEAK]
EXPORT SPIM2_SPIS2_SPI2_IRQHandler [WEAK]
EXPORT RTC2_IRQHandler [WEAK]
EXPORT I2S_IRQHandler [WEAK]
EXPORT FPU_IRQHandler [WEAK]
POWER_CLOCK_IRQHandler
RADIO_IRQHandler
UARTE0_UART0_IRQHandler
SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQHandler
SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1_IRQHandler
NFCT_IRQHandler
GPIOTE_IRQHandler
SAADC_IRQHandler
TIMER0_IRQHandler
TIMER1_IRQHandler
TIMER2_IRQHandler
RTC0_IRQHandler
TEMP_IRQHandler
RNG_IRQHandler
ECB_IRQHandler
CCM_AAR_IRQHandler
WDT_IRQHandler
RTC1_IRQHandler
QDEC_IRQHandler
COMP_LPCOMP_IRQHandler
SWI0_EGU0_IRQHandler
SWI1_EGU1_IRQHandler
SWI2_EGU2_IRQHandler
SWI3_EGU3_IRQHandler
SWI4_EGU4_IRQHandler
SWI5_EGU5_IRQHandler
TIMER3_IRQHandler
TIMER4_IRQHandler
PWM0_IRQHandler
PDM_IRQHandler
MWU_IRQHandler
PWM1_IRQHandler
PWM2_IRQHandler
SPIM2_SPIS2_SPI2_IRQHandler
RTC2_IRQHandler
I2S_IRQHandler
FPU_IRQHandler
B .
ENDP
ALIGN
; User Initial Stack & Heap
IF :DEF:__MICROLIB
EXPORT __initial_sp
EXPORT __heap_base
EXPORT __heap_limit
ELSE
IMPORT __use_two_region_memory
EXPORT __user_initial_stackheap
__user_initial_stackheap PROC
LDR R0, = Heap_Mem
LDR R1, = (Stack_Mem + Stack_Size)
LDR R2, = (Heap_Mem + Heap_Size)
LDR R3, = Stack_Mem
BX LR
ENDP
ALIGN
ENDIF
END

View File

@@ -0,0 +1,51 @@
/*
Copyright (c) 2010 - 2018, 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 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.
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 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.
*/
/* Configure stack size, stack alignement and heap size with a header file instead of project settings or modification of Nordic provided assembler files. Modify this file as needed. */
/* In order to make use this file,
1. For Keil uVision IDE, in the Options for Target -> Asm tab, define symbol __STARTUP_CONFIG and use the additional assembler option --cpreproc in Misc Control text box.
2. For GCC compiling, add extra assembly option -D__STARTUP_CONFIG.
3. For IAR Embedded Workbench define symbol __STARTUP_CONFIG in the Assembler options and define symbol __STARTUP_CONFIG=1 in the linker options.
*/
/* This file is a template and should be copied to the project directory. */
/* Define size of stack. Size must be multiple of 4. */
#define __STARTUP_CONFIG_STACK_SIZE 0x1000
/* Define alignement of stack. Alignment will be 2 to the power of __STARTUP_CONFIG_STACK_ALIGNEMENT. Since calling convention requires that the stack is aligned to 8-bytes when a function is called, the minimum __STARTUP_CONFIG_STACK_ALIGNEMENT is therefore 3. */
#define __STARTUP_CONFIG_STACK_ALIGNEMENT 3
/* Define size of heap. Size must be multiple of 4. */
#define __STARTUP_CONFIG_HEAP_SIZE 0x1000

View File

@@ -0,0 +1,373 @@
/*
Copyright (c) 2009-2018 ARM Limited. All rights reserved.
SPDX-License-Identifier: Apache-2.0
Licensed 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
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.
NOTICE: This file has been modified by Nordic Semiconductor ASA.
*/
/* NOTE: Template files (including this one) are application specific and therefore expected to
be copied into the application project folder prior to its use! */
#include <stdint.h>
#include <stdbool.h>
#include "nrf.h"
#include "system_nrf52.h"
/*lint ++flb "Enter library region" */
#define __SYSTEM_CLOCK_64M (64000000UL)
static bool errata_12(void);
static bool errata_16(void);
static bool errata_31(void);
static bool errata_32(void);
static bool errata_36(void);
static bool errata_37(void);
static bool errata_57(void);
static bool errata_66(void);
static bool errata_108(void);
static bool errata_136(void);
static bool errata_182(void);
#if defined ( __CC_ARM )
uint32_t SystemCoreClock __attribute__((used)) = __SYSTEM_CLOCK_64M;
#elif defined ( __ICCARM__ )
__root uint32_t SystemCoreClock = __SYSTEM_CLOCK_64M;
#elif defined ( __GNUC__ )
uint32_t SystemCoreClock __attribute__((used)) = __SYSTEM_CLOCK_64M;
#endif
void SystemCoreClockUpdate(void)
{
SystemCoreClock = __SYSTEM_CLOCK_64M;
}
void SystemInit(void)
{
/* Enable SWO trace functionality. If ENABLE_SWO is not defined, SWO pin will be used as GPIO (see Product
Specification to see which one). */
#if defined (ENABLE_SWO)
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
NRF_CLOCK->TRACECONFIG |= CLOCK_TRACECONFIG_TRACEMUX_Serial << CLOCK_TRACECONFIG_TRACEMUX_Pos;
NRF_P0->PIN_CNF[18] = (GPIO_PIN_CNF_DRIVE_H0H1 << GPIO_PIN_CNF_DRIVE_Pos) | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos);
#endif
/* Enable Trace functionality. If ENABLE_TRACE is not defined, TRACE pins will be used as GPIOs (see Product
Specification to see which ones). */
#if defined (ENABLE_TRACE)
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
NRF_CLOCK->TRACECONFIG |= CLOCK_TRACECONFIG_TRACEMUX_Parallel << CLOCK_TRACECONFIG_TRACEMUX_Pos;
NRF_P0->PIN_CNF[14] = (GPIO_PIN_CNF_DRIVE_H0H1 << GPIO_PIN_CNF_DRIVE_Pos) | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos);
NRF_P0->PIN_CNF[15] = (GPIO_PIN_CNF_DRIVE_H0H1 << GPIO_PIN_CNF_DRIVE_Pos) | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos);
NRF_P0->PIN_CNF[16] = (GPIO_PIN_CNF_DRIVE_H0H1 << GPIO_PIN_CNF_DRIVE_Pos) | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos);
NRF_P0->PIN_CNF[18] = (GPIO_PIN_CNF_DRIVE_H0H1 << GPIO_PIN_CNF_DRIVE_Pos) | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos);
NRF_P0->PIN_CNF[20] = (GPIO_PIN_CNF_DRIVE_H0H1 << GPIO_PIN_CNF_DRIVE_Pos) | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos);
#endif
/* Workaround for Errata 12 "COMP: Reference ladder not correctly calibrated" found at the Errata document
for your device located at https://www.nordicsemi.com/DocLib */
if (errata_12()){
*(volatile uint32_t *)0x40013540 = (*(uint32_t *)0x10000324 & 0x00001F00) >> 8;
}
/* Workaround for Errata 16 "System: RAM may be corrupt on wakeup from CPU IDLE" found at the Errata document
for your device located at https://www.nordicsemi.com/DocLib */
if (errata_16()){
*(volatile uint32_t *)0x4007C074 = 3131961357ul;
}
/* Workaround for Errata 31 "CLOCK: Calibration values are not correctly loaded from FICR at reset" found at the Errata document
for your device located at https://www.nordicsemi.com/DocLib */
if (errata_31()){
*(volatile uint32_t *)0x4000053C = ((*(volatile uint32_t *)0x10000244) & 0x0000E000) >> 13;
}
/* Workaround for Errata 32 "DIF: Debug session automatically enables TracePort pins" found at the Errata document
for your device located at https://www.nordicsemi.com/DocLib */
if (errata_32()){
CoreDebug->DEMCR &= ~CoreDebug_DEMCR_TRCENA_Msk;
}
/* Workaround for Errata 36 "CLOCK: Some registers are not reset when expected" found at the Errata document
for your device located at https://www.nordicsemi.com/DocLib */
if (errata_36()){
NRF_CLOCK->EVENTS_DONE = 0;
NRF_CLOCK->EVENTS_CTTO = 0;
NRF_CLOCK->CTIV = 0;
}
/* Workaround for Errata 37 "RADIO: Encryption engine is slow by default" found at the Errata document
for your device located at https://www.nordicsemi.com/DocLib */
if (errata_37()){
*(volatile uint32_t *)0x400005A0 = 0x3;
}
/* Workaround for Errata 57 "NFCT: NFC Modulation amplitude" found at the Errata document
for your device located at https://www.nordicsemi.com/DocLib */
if (errata_57()){
*(volatile uint32_t *)0x40005610 = 0x00000005;
*(volatile uint32_t *)0x40005688 = 0x00000001;
*(volatile uint32_t *)0x40005618 = 0x00000000;
*(volatile uint32_t *)0x40005614 = 0x0000003F;
}
/* Workaround for Errata 66 "TEMP: Linearity specification not met with default settings" found at the Errata document
for your device located at https://www.nordicsemi.com/DocLib */
if (errata_66()){
NRF_TEMP->A0 = NRF_FICR->TEMP.A0;
NRF_TEMP->A1 = NRF_FICR->TEMP.A1;
NRF_TEMP->A2 = NRF_FICR->TEMP.A2;
NRF_TEMP->A3 = NRF_FICR->TEMP.A3;
NRF_TEMP->A4 = NRF_FICR->TEMP.A4;
NRF_TEMP->A5 = NRF_FICR->TEMP.A5;
NRF_TEMP->B0 = NRF_FICR->TEMP.B0;
NRF_TEMP->B1 = NRF_FICR->TEMP.B1;
NRF_TEMP->B2 = NRF_FICR->TEMP.B2;
NRF_TEMP->B3 = NRF_FICR->TEMP.B3;
NRF_TEMP->B4 = NRF_FICR->TEMP.B4;
NRF_TEMP->B5 = NRF_FICR->TEMP.B5;
NRF_TEMP->T0 = NRF_FICR->TEMP.T0;
NRF_TEMP->T1 = NRF_FICR->TEMP.T1;
NRF_TEMP->T2 = NRF_FICR->TEMP.T2;
NRF_TEMP->T3 = NRF_FICR->TEMP.T3;
NRF_TEMP->T4 = NRF_FICR->TEMP.T4;
}
/* Workaround for Errata 108 "RAM: RAM content cannot be trusted upon waking up from System ON Idle or System OFF mode" found at the Errata document
for your device located at https://www.nordicsemi.com/DocLib */
if (errata_108()){
*(volatile uint32_t *)0x40000EE4 = *(volatile uint32_t *)0x10000258 & 0x0000004F;
}
/* Workaround for Errata 136 "System: Bits in RESETREAS are set when they should not be" found at the Errata document
for your device located at https://www.nordicsemi.com/DocLib */
if (errata_136()){
if (NRF_POWER->RESETREAS & POWER_RESETREAS_RESETPIN_Msk){
NRF_POWER->RESETREAS = ~POWER_RESETREAS_RESETPIN_Msk;
}
}
/* Workaround for Errata 182 "RADIO: Fixes for anomalies #102, #106, and #107 do not take effect" found at the Errata document
for your device located at https://www.nordicsemi.com/DocLib */
if (errata_182()){
*(volatile uint32_t *) 0x4000173C |= (0x1 << 10);
}
/* Enable the FPU if the compiler used floating point unit instructions. __FPU_USED is a MACRO defined by the
* compiler. Since the FPU consumes energy, remember to disable FPU use in the compiler if floating point unit
* operations are not used in your code. */
#if (__FPU_USED == 1)
SCB->CPACR |= (3UL << 20) | (3UL << 22);
__DSB();
__ISB();
#endif
/* Configure NFCT pins as GPIOs if NFCT is not to be used in your code. If CONFIG_NFCT_PINS_AS_GPIOS is not defined,
two GPIOs (see Product Specification to see which ones) will be reserved for NFC and will not be available as
normal GPIOs. */
#if defined (CONFIG_NFCT_PINS_AS_GPIOS)
if ((NRF_UICR->NFCPINS & UICR_NFCPINS_PROTECT_Msk) == (UICR_NFCPINS_PROTECT_NFC << UICR_NFCPINS_PROTECT_Pos)){
NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Wen << NVMC_CONFIG_WEN_Pos;
while (NRF_NVMC->READY == NVMC_READY_READY_Busy){}
NRF_UICR->NFCPINS &= ~UICR_NFCPINS_PROTECT_Msk;
while (NRF_NVMC->READY == NVMC_READY_READY_Busy){}
NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Ren << NVMC_CONFIG_WEN_Pos;
while (NRF_NVMC->READY == NVMC_READY_READY_Busy){}
NVIC_SystemReset();
}
#endif
/* Configure GPIO pads as pPin Reset pin if Pin Reset capabilities desired. If CONFIG_GPIO_AS_PINRESET is not
defined, pin reset will not be available. One GPIO (see Product Specification to see which one) will then be
reserved for PinReset and not available as normal GPIO. */
#if defined (CONFIG_GPIO_AS_PINRESET)
if (((NRF_UICR->PSELRESET[0] & UICR_PSELRESET_CONNECT_Msk) != (UICR_PSELRESET_CONNECT_Connected << UICR_PSELRESET_CONNECT_Pos)) ||
((NRF_UICR->PSELRESET[1] & UICR_PSELRESET_CONNECT_Msk) != (UICR_PSELRESET_CONNECT_Connected << UICR_PSELRESET_CONNECT_Pos))){
NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Wen << NVMC_CONFIG_WEN_Pos;
while (NRF_NVMC->READY == NVMC_READY_READY_Busy){}
NRF_UICR->PSELRESET[0] = 21;
while (NRF_NVMC->READY == NVMC_READY_READY_Busy){}
NRF_UICR->PSELRESET[1] = 21;
while (NRF_NVMC->READY == NVMC_READY_READY_Busy){}
NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Ren << NVMC_CONFIG_WEN_Pos;
while (NRF_NVMC->READY == NVMC_READY_READY_Busy){}
NVIC_SystemReset();
}
#endif
SystemCoreClockUpdate();
}
static bool errata_12(void)
{
if ((((*(uint32_t *)0xF0000FE0) & 0x000000FF) == 0x6) && (((*(uint32_t *)0xF0000FE4) & 0x0000000F) == 0x0)){
if (((*(uint32_t *)0xF0000FE8) & 0x000000F0) == 0x30){
return true;
}
if (((*(uint32_t *)0xF0000FE8) & 0x000000F0) == 0x40){
return true;
}
if (((*(uint32_t *)0xF0000FE8) & 0x000000F0) == 0x50){
return true;
}
}
return false;
}
static bool errata_16(void)
{
if ((((*(uint32_t *)0xF0000FE0) & 0x000000FF) == 0x6) && (((*(uint32_t *)0xF0000FE4) & 0x0000000F) == 0x0)){
if (((*(uint32_t *)0xF0000FE8) & 0x000000F0) == 0x30){
return true;
}
}
return false;
}
static bool errata_31(void)
{
if ((((*(uint32_t *)0xF0000FE0) & 0x000000FF) == 0x6) && (((*(uint32_t *)0xF0000FE4) & 0x0000000F) == 0x0)){
if (((*(uint32_t *)0xF0000FE8) & 0x000000F0) == 0x30){
return true;
}
if (((*(uint32_t *)0xF0000FE8) & 0x000000F0) == 0x40){
return true;
}
if (((*(uint32_t *)0xF0000FE8) & 0x000000F0) == 0x50){
return true;
}
}
return false;
}
static bool errata_32(void)
{
if ((((*(uint32_t *)0xF0000FE0) & 0x000000FF) == 0x6) && (((*(uint32_t *)0xF0000FE4) & 0x0000000F) == 0x0)){
if (((*(uint32_t *)0xF0000FE8) & 0x000000F0) == 0x30){
return true;
}
}
return false;
}
static bool errata_36(void)
{
if ((((*(uint32_t *)0xF0000FE0) & 0x000000FF) == 0x6) && (((*(uint32_t *)0xF0000FE4) & 0x0000000F) == 0x0)){
if (((*(uint32_t *)0xF0000FE8) & 0x000000F0) == 0x30){
return true;
}
if (((*(uint32_t *)0xF0000FE8) & 0x000000F0) == 0x40){
return true;
}
if (((*(uint32_t *)0xF0000FE8) & 0x000000F0) == 0x50){
return true;
}
}
return false;
}
static bool errata_37(void)
{
if ((((*(uint32_t *)0xF0000FE0) & 0x000000FF) == 0x6) && (((*(uint32_t *)0xF0000FE4) & 0x0000000F) == 0x0)){
if (((*(uint32_t *)0xF0000FE8) & 0x000000F0) == 0x30){
return true;
}
}
return false;
}
static bool errata_57(void)
{
if ((((*(uint32_t *)0xF0000FE0) & 0x000000FF) == 0x6) && (((*(uint32_t *)0xF0000FE4) & 0x0000000F) == 0x0)){
if (((*(uint32_t *)0xF0000FE8) & 0x000000F0) == 0x30){
return true;
}
}
return false;
}
static bool errata_66(void)
{
if ((((*(uint32_t *)0xF0000FE0) & 0x000000FF) == 0x6) && (((*(uint32_t *)0xF0000FE4) & 0x0000000F) == 0x0)){
if (((*(uint32_t *)0xF0000FE8) & 0x000000F0) == 0x50){
return true;
}
}
return false;
}
static bool errata_108(void)
{
if ((((*(uint32_t *)0xF0000FE0) & 0x000000FF) == 0x6) && (((*(uint32_t *)0xF0000FE4) & 0x0000000F) == 0x0)){
if (((*(uint32_t *)0xF0000FE8) & 0x000000F0) == 0x30){
return true;
}
if (((*(uint32_t *)0xF0000FE8) & 0x000000F0) == 0x40){
return true;
}
if (((*(uint32_t *)0xF0000FE8) & 0x000000F0) == 0x50){
return true;
}
}
return false;
}
static bool errata_136(void)
{
if ((((*(uint32_t *)0xF0000FE0) & 0x000000FF) == 0x6) && (((*(uint32_t *)0xF0000FE4) & 0x0000000F) == 0x0)){
if (((*(uint32_t *)0xF0000FE8) & 0x000000F0) == 0x30){
return true;
}
if (((*(uint32_t *)0xF0000FE8) & 0x000000F0) == 0x40){
return true;
}
if (((*(uint32_t *)0xF0000FE8) & 0x000000F0) == 0x50){
return true;
}
}
return false;
}
static bool errata_182(void)
{
if (*(uint32_t *)0x10000130ul == 0x6ul){
if (*(uint32_t *)0x10000134ul == 0x6ul){
return true;
}
}
return false;
}
/*lint --flb "Leave library region" */

View File

@@ -0,0 +1,20 @@
/*
* Auto generated Run-Time-Environment Component Configuration File
* *** Do not modify ! ***
*
* Project: 'ble_app_blinky_pca10040_s132'
* Target: 'nrf52832_xxaa'
*/
#ifndef RTE_COMPONENTS_H
#define RTE_COMPONENTS_H
/*
* Define the Device Header File:
*/
#define CMSIS_device_header "nrf.h"
#endif /* RTE_COMPONENTS_H */

View File

@@ -0,0 +1,7 @@
# 说明
1. 本工程基于 nRF52832 平台开发,使用的 SDK 版本为 `nRF5_SDK_15.3.0_59ac345`,如需其他版本 SDK请前往 [NORDIC 官网](https://www.nordicsemi.com/Software-and-tools/Software/nRF5-SDK/Download) 下载
2. 蓝牙协议栈为 s132 版本,在 NORDIC SDK 中的路径为 `\components\softdevice\s132\hex\s132_nrf52_6.1.1_softdevice.hex`,请根据实际需要自行烧录协议栈
3. Keil工程的DeviceFamilyPack为 `NordicSemiconductor.nRF_DeviceFamilyPack.8.24.1.pack`,如需其他 pack 请前往 [NORDIC 官网](http://developer.nordicsemi.com/nRF51_SDK/pieces/nRF_DeviceFamilyPack/) 下载
4. 例程keil工程文件路径 `\qcloud_iot_explorer_ble\samples\nrf52832\pca10040\s132\arm5_no_packs`
5. 使用 code_extract.py 脚本抽取代码得到 `qcloud-iot-ble-nrf52832` 目录,请将该目录放置 NORDIC SDK 的 `\examples\ble_peripheral` 目录下打开keil工程编译即可

View File

@@ -0,0 +1,74 @@
#!/usr/bin/python
# -*- coding: UTF-8 -*-
import sys
import os
import shutil
demo_dir_prefix = 'qcloud-iot-ble-'
script_path = os.path.split(os.path.realpath(__file__))[0]
sdk_path = os.path.join(script_path, '..', '..')
def extract_nrf2832(dest_dir):
print('extract code for nrf52832 start, dest dir %s' % dest_dir)
if os.path.exists(dest_dir):
shutil.rmtree(dest_dir)
shutil.copytree(os.path.join(sdk_path, 'samples', 'nrf52832'), dest_dir)
new_sdk_path = os.path.join(dest_dir, 'qcloud_iot_explorer_ble')
shutil.copytree(os.path.join(sdk_path, 'inc'), os.path.join(new_sdk_path, 'inc'))
shutil.copytree(os.path.join(sdk_path, 'src'), os.path.join(new_sdk_path, 'src'))
print('extract code success')
pass
def extract_esp32(dest_dir):
print('extract code for esp32, dest dir %s' % dest_dir)
if os.path.exists(dest_dir):
shutil.rmtree(dest_dir)
shutil.copytree(os.path.join(sdk_path, 'samples', 'esp32'), dest_dir)
new_sdk_path = os.path.join(dest_dir, 'components', 'qcloud_llsync')
shutil.copytree(os.path.join(sdk_path, 'inc'), os.path.join(new_sdk_path, 'inc'))
shutil.copytree(os.path.join(sdk_path, 'src'), os.path.join(new_sdk_path, 'src'))
print('extract code success')
pass
def extract_lifesense(dest_dir):
print('extract code for lifesense, dest dir %s' % dest_dir)
if os.path.exists(dest_dir):
shutil.rmtree(dest_dir)
shutil.copytree(os.path.join(sdk_path, 'samples', 'lifesense'), dest_dir)
new_sdk_path = os.path.join(dest_dir, 'qcloud_iot_explorer_ble')
shutil.copytree(os.path.join(sdk_path, 'inc'), os.path.join(new_sdk_path, 'inc'))
shutil.copytree(os.path.join(sdk_path, 'src'), os.path.join(new_sdk_path, 'src'))
print('extract code success')
pass
if __name__ == '__main__':
if len(sys.argv) < 2:
print('\nUsage: python3 %s <platform> [dest dir]' % sys.argv[0])
print('\nDefinitions:')
print('<platform>\t%s' % 'Device type. The following are allowed: nrf52832, esp32, lefesense')
print('[dest dir]\t%s %s\n' % ('Where the code stored. Default path: ', script_path))
else:
if len(sys.argv) == 2:
dest_dir = os.path.join(script_path, demo_dir_prefix + sys.argv[1])
else:
dest_dir = os.path.join(sys.argv[2], demo_dir_prefix + sys.argv[1])
if 'nrf52832' == sys.argv[1]:
extract_nrf2832(dest_dir)
elif 'esp32' == sys.argv[1]:
extract_esp32(dest_dir)
elif 'lifesense' == sys.argv[1]:
extract_lifesense(dest_dir)
else:
print('Unknow platform %s, extract failed' % sys.argv[1])
pass

View File

@@ -0,0 +1,109 @@
# 文件统一定义
[FILE]
COPYRIGHT = /*
* 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.
*
*/
NAME_PREFIX = ble_qiot_template
MACRO_PREFIX = BLE_QIOT_
ENUM_PREFIX = BLE_QIOT_
# json文本内健定义
[JSON]
VERSION = version
PROPERTY = properties
MODE = mode
EVENT = events
TYPE = type
PARAMS = params
ACTION = actions
INPUT = input
OUTPUT = output
ID = id
DEFINE = define
MAPPING = mapping
UNIT = unit
BOOL = bool
ENUM = enum
STRING = string
FLOAT = float
INT = int
TIME = timestamp
# 数据类型定义
# 左侧数值表示实际数值默认从0开始枚举
# BUTT表示最大值
[DATA_TYPE]
0 = BOOL
1 = INT
2 = STRING
3 = FLOAT
4 = ENUM
5 = TIME
6 = BUTT
# 消息类型定义
# 左侧数值表示实际数值默认从0开始枚举
# BUTT表示最大值
[MSG_TYPE]
0 = PROPERTY
1 = EVENT
2 = ACTION
3 = BUTT
# Property 读写属性定义
# 左侧数值表示实际数值默认从0开始枚举
# BUTT表示最大值
[PROPERTY_AUTH]
0 = RW
1 = READ
2 = BUTT
# 数据功能,请求 or 回复
# 左侧数值表示实际数值默认从0开始枚举
# BUTT表示最大值
[EFFECT]
0= REQUEST
1 = REPLY
2 = BUTT
# Reply消息结果定义
# 左侧数值表示实际数值默认从0开始枚举
# BUTT表示最大值
[REPLY]
0 = SUCCESS
1 = FAIL
2 = DATA_ERR
3 = BUTT
# 服务端向设备端下发消息类型定义
# 左侧数值表示实际数值默认从0开始枚举
# BUTT表示最大值
[DATA_DOWN]
0 = REPORT_REPLY
1 = CONTROL
2 = GET_STATUS_REPLY
3 = ACTION
4 = EVENT_REPLY
# 设备端向服务端上报消息类型定义
# 左侧数值表示实际数值默认从0开始枚举
# BUTT表示最大值
[EVENT_UP]
0 = PROPERTY_REPORT
1 = CONTROL_REPLY
2 = GET_STATUS
3 = EVENT_POST
4 = ACTION_REPLY
5 = BIND_SIGN_RET
6 = CONN_SIGN_RET
7 = UNBIND_SIGN_RET
8 = REPORT_MTU
9 = BUTT

View File

@@ -0,0 +1,60 @@
## 介绍
使用`python`脚本将后台生成的`json`格式的数据模版文件转为`c`代码文件。
极大的减少了用户的开发工作,同时保证了终端设备,网关设备上数据定义的一致性。
请使用`python3`解释器运行。
## 目录结构
```c
interpret_json_dt
config #
dt.conf # INI配置文件
src #
dt_fixed_content #
dt_ble_action # ble action部分固定代码
dt_ble_event # ble event部分固定代码
dt_ble_property # ble proerty部分固定代码
dt_ble_prototype # ble
dt_gateway_action # gateway action部分固定代码
dt_gateway_event # gateway event部分固定代码
dt_gateway_property # gateway property部分固定代码
dt_gateway_prototype # gateway
interpret_dt_ble.py # json脚本生成ble sdk代码
interpret_dt_gateway.py # json脚本生成网关代码
example.json #
```
## 代码生成原理
采取`动态生成 + 固定写入`的方式来生成代码。
* 动态生成:通过脚本解析`json`文件,将数据模版转换为对应的代码
* 固定写入:数据模版的操作函数是固定不变的,从静态文件读取写入,达到简化脚本的目的
### 头文件生成
1. 按照`LLSync协议`定义写入公共定义,包括数据类型定义,消息类型定义等
2. 解析`json`文件,将字符串`id`转换为枚举类型`id`
3. 将每个`id`对应的值根据其类型进行转换
* 对于枚举类型,将其枚举值转换为枚举类型
* 对于整数类型或浮点数类型,将其最大值,最小值,起始值,步进转换为宏定义
* 对于字符串类型,将其最大长度,最小长度转换为宏定义
4. 写入不同数据类型的结构体定义
5. 写入不同数据类型的函数声明,函数声明从`dt_gateway_prototype`中读
### BLE C文件生成
1. 解析`json`文件,根据`id`生成其操作函数,**操作函数需要用户按照需求实现**
2. 解析`json`文件,生成数据模版的结构数组
3. 读取静态文件,写入固定操作函数
### 网关C文件生成
1. 解析`json`文件,生成数据模版的结构数组
2. 读取静态文件,写入固定操作函数
## 使用方法
### BLE SDK
1. 从物联网平台下载数据模版`json`文件
2. 执行`python3 interpret_dt_ble.py <your_json_file>`来生成对应的数据模版文件
3. 按照数据特性实现`ble_qiot_template.c`中的操作函数
4. 将生成文件拷贝到`data_template`目录编译即可
### 网关
1. 从物联网平台下载数据模版`json`文件
2. 执行`python3 interpret_dt_gateway.py <your_json_file>`来生成对应的数据模版文件
3. 将生成文件拷贝SDK编译即可。

View File

@@ -0,0 +1,96 @@
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;
}
}
}

View File

@@ -0,0 +1,65 @@
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", event_id, param_id);
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;
}

View File

@@ -0,0 +1,105 @@
static bool ble_check_space_enough_by_type(uint8_t type, uint16_t left_size)
{
switch(type)
{
case BLE_QIOT_DATA_TYPE_BOOL:
return left_size >= sizeof(uint8_t);
case BLE_QIOT_DATA_TYPE_INT:
case BLE_QIOT_DATA_TYPE_FLOAT:
case BLE_QIOT_DATA_TYPE_TIME:
return left_size >= sizeof(uint32_t);
case BLE_QIOT_DATA_TYPE_ENUM:
return left_size >= sizeof(uint16_t);
default:
// string length is unknow, default true
return true;
}
}
static uint16_t ble_check_ret_value_by_type(uint8_t type, uint16_t buf_len, uint16_t ret_val)
{
switch(type)
{
case BLE_QIOT_DATA_TYPE_BOOL:
return ret_val <= sizeof(uint8_t);
case BLE_QIOT_DATA_TYPE_INT:
case BLE_QIOT_DATA_TYPE_FLOAT:
case BLE_QIOT_DATA_TYPE_TIME:
return ret_val <= sizeof(uint32_t);
case BLE_QIOT_DATA_TYPE_ENUM:
return ret_val <= sizeof(uint16_t);
default:
// string length is unknow, default true
return ret_val <= buf_len;
}
}
uint8_t ble_get_property_type_by_id(uint8_t id)
{
if (id >= BLE_QIOT_PROPERTY_ID_BUTT) {
ble_qiot_log_e("invalid property id %d", id);
return BLE_QIOT_DATA_TYPE_BUTT;
}
return sg_ble_property_array[id].type;
}
int ble_user_property_set_data(const e_ble_tlv *tlv)
{
POINTER_SANITY_CHECK(tlv, BLE_QIOT_RS_ERR_PARA);
if (tlv->id >= BLE_QIOT_PROPERTY_ID_BUTT) {
ble_qiot_log_e("invalid property id %d", tlv->id);
return BLE_QIOT_RS_ERR;
}
if (NULL != sg_ble_property_array[tlv->id].set_cb) {
if (0 != sg_ble_property_array[tlv->id].set_cb(tlv->val, tlv->len)) {
ble_qiot_log_e("set property id %d failed", tlv->id);
return BLE_QIOT_RS_ERR;
}else {
return BLE_QIOT_RS_OK;
}
}
ble_qiot_log_e("invalid set callback, id %d", tlv->id);
return BLE_QIOT_RS_ERR;
}
int ble_user_property_get_data_by_id(uint8_t id, char *buf, uint16_t buf_len)
{
int ret_len = 0;
POINTER_SANITY_CHECK(buf, BLE_QIOT_RS_ERR_PARA);
if (id >= BLE_QIOT_PROPERTY_ID_BUTT) {
ble_qiot_log_e("invalid property id %d", id);
return -1;
}
if (NULL != sg_ble_property_array[id].get_cb) {
if (!ble_check_space_enough_by_type(sg_ble_property_array[id].type, buf_len)) {
ble_qiot_log_e("not enough space get property id %d data", id);
return -1;
}
ret_len = sg_ble_property_array[id].get_cb(buf, buf_len);
if (ret_len < 0) {
ble_qiot_log_e("get property id %d data failed", id);
return -1;
}else {
if (ble_check_ret_value_by_type(sg_ble_property_array[id].type, buf_len, ret_len)){
return ret_len;
}else{
ble_qiot_log_e("property id %d length invalid", id);
return -1;
}
}
}
ble_qiot_log_e("invalid callback, property id %d", id);
return 0;
}
int ble_user_property_report_reply_handle(uint8_t result)
{
ble_qiot_log_d("report reply result %d", result);
return BLE_QIOT_RS_OK;
}

View File

@@ -0,0 +1,25 @@
// property module
#ifdef BLE_QIOT_INCLUDE_PROPERTY
uint8_t ble_get_property_type_by_id(uint8_t id);
int ble_user_property_set_data(const e_ble_tlv *tlv);
int ble_user_property_get_data_by_id(uint8_t id, char *buf, uint16_t buf_len);
int ble_user_property_report_reply_handle(uint8_t result);
#endif
// event module
#ifdef BLE_QIOT_INCLUDE_EVENT
int ble_event_get_id_array_size(uint8_t event_id);
uint8_t ble_event_get_param_id_type(uint8_t event_id, uint8_t param_id);
int ble_event_get_data_by_id(uint8_t event_id, uint8_t param_id, char *out_buf, uint16_t buf_len);
int ble_user_event_reply_handle(uint8_t event_id, uint8_t result);
#endif
// action module
#ifdef BLE_QIOT_INCLUDE_ACTION
uint8_t ble_action_get_intput_type_by_id(uint8_t action_id, uint8_t input_id);
uint8_t ble_action_get_output_type_by_id(uint8_t action_id, uint8_t output_id);
int ble_action_get_input_id_size(uint8_t action_id);
int ble_action_get_output_id_size(uint8_t action_id);
int ble_action_user_handle_input_param(uint8_t action_id, e_ble_tlv *input_param_array, uint8_t input_array_size, uint8_t *output_id_array);
int ble_action_user_handle_output_param(uint8_t action_id, uint8_t output_id, char *buf, uint16_t buf_len);
#endif

View File

@@ -0,0 +1,607 @@
#!/usr/bin/python
# -*- coding: UTF-8 -*-
import sys
import json
import os
import configparser
script_path = os.path.split(os.path.realpath(__file__))[0]
dt_config = configparser.ConfigParser()
def _dt_get_config_from_file():
config_file = open(os.path.join(script_path, '..', 'config', 'dt.conf'), 'r', encoding='UTF-8')
config_content = config_file.read()
config_file.close()
dt_config.read_string(config_content)
pass
def _dt_get_json_from_file(filenmae):
_dt_get_config_from_file()
json_file = open(filenmae, 'r', encoding='UTF-8')
file_content = json_file.read()
json_file.close()
return json.loads(file_content)
def _dt_write_newline_to_file(write_fd, write_buf):
write_fd.writelines(write_buf + '\n')
pass
def _dt_write_macro_to_file(write_fd, macro, macro_val):
write_fd.writelines('#define\t%-40s\t%-32s\n' % (dt_config['FILE']['MACRO_PREFIX'] +
macro.upper(), macro_val.upper()))
pass
def _dt_write_enum_to_file(write_fd, enum_comments, enum_prefix, enum_suffix_list, enum_value_list=None):
init_flag = True
write_fd.writelines('\n' + enum_comments + '\n')
write_fd.writelines('enum {\n')
if enum_value_list == None:
for enum_suffix in enum_suffix_list:
if init_flag:
write_fd.writelines('\t' + dt_config['FILE']['ENUM_PREFIX'] +
(enum_prefix + '_' + enum_suffix).upper() + ' = 0,\n')
init_flag = False
else:
write_fd.writelines('\t' + dt_config['FILE']['ENUM_PREFIX'] +
(enum_prefix + '_' + enum_suffix).upper() + ',\n')
else:
for idx, enum_suffix in enumerate(enum_suffix_list):
write_fd.writelines('\t' + dt_config['FILE']['ENUM_PREFIX'] +
(enum_prefix + '_' + enum_suffix).upper() + ' = %s,\n' % enum_value_list[idx])
write_fd.writelines('};\n')
pass
def _dt_get_enum_list_from_conf(conf_data):
return [v for k, v in conf_data.items()]
def _dt_get_enum_list_from_ids(property_json):
id_list = [value.get('id') for value in property_json]
id_list.append('BUTT')
return id_list
def _dt_get_enum_list_from_mapping(mapping):
new_list = sorted(mapping.keys())
enum_prefix = [mapping[key] for key in new_list]
enum_prefix.append('BUTT')
enum_val = [key for key in new_list]
enum_val.append(str(int(new_list[-1]) + 1))
return [enum_prefix, enum_val]
def _dt_not_exist(dt_data):
if not dt_data:
return True
else:
return False
def _dt_write_public_header(write_fd):
_dt_write_enum_to_file(write_fd, '// data type in template, corresponding to type in json file',
dt_config['DATA_TYPE'].name,
_dt_get_enum_list_from_conf(dt_config['DATA_TYPE']))
_dt_write_enum_to_file(write_fd, '// message type, reference data template ', dt_config['MSG_TYPE'].name,
_dt_get_enum_list_from_conf(dt_config['MSG_TYPE']))
_dt_write_enum_to_file(write_fd, '// define property authority, not used', dt_config['PROPERTY_AUTH'].name,
_dt_get_enum_list_from_conf(dt_config['PROPERTY_AUTH']))
_dt_write_enum_to_file(write_fd, '// define reply result', dt_config['REPLY'].name,
_dt_get_enum_list_from_conf(dt_config['REPLY']))
_dt_write_enum_to_file(write_fd, '// define message flow direction', dt_config['EFFECT'].name,
_dt_get_enum_list_from_conf(dt_config['EFFECT']))
_dt_write_enum_to_file(write_fd, '// define message type that from server to device', dt_config['DATA_DOWN'].name,
_dt_get_enum_list_from_conf(dt_config['DATA_DOWN']))
_dt_write_enum_to_file(write_fd, '// define message type that from device to server', dt_config['EVENT_UP'].name,
_dt_get_enum_list_from_conf(dt_config['EVENT_UP']))
_dt_write_newline_to_file(write_fd,
'\n// msg header define, bit 7-6 is msg type, bit 5 means request or reply, bit 4 - 0 is id')
_dt_write_macro_to_file(write_fd, 'PARSE_MSG_HEAD_TYPE(_c)', '(((_c) & 0xFF) >> 6)')
_dt_write_macro_to_file(write_fd, 'PARSE_MSG_HEAD_EFFECT(_c)',
'((((_c) & 0xFF) & 0x20) ? BLE_QIOT_EFFECT_REPLY : BLE_QIOT_EFFECT_REQUEST)')
_dt_write_macro_to_file(write_fd, 'PARSE_MSG_HEAD_ID(_c)', '((_c) & 0x1F)')
_dt_write_macro_to_file(write_fd, 'PACKAGE_MSG_HEAD(_type, _reply, _id)',
'(((_type) << 6) | (((_reply) == BLE_QIOT_EFFECT_REPLY) << 5) | ((_id) & 0x1F))')
_dt_write_newline_to_file(write_fd,
'\n// tlv header define, bit 7 - 5 is type, bit 4 - 0 depends on type of data template')
_dt_write_macro_to_file(write_fd, 'PARSE_TLV_HEAD_TYPE(_c)', '(((_c) & 0xFF) >> 5)')
_dt_write_macro_to_file(write_fd, 'PARSE_TLV_HEAD_ID(_c)', '((_c) & 0x1F)')
_dt_write_macro_to_file(write_fd, 'PACKAGE_TLV_HEAD(_type, _id)', '(((_type) << 5) | ((_id) & 0x1F))\n')
_dt_write_newline_to_file(write_fd, '\n// define tlv struct')
_dt_write_newline_to_file(write_fd, 'typedef struct{'
'\n\tuint8_t type;'
'\n\tuint8_t id;'
'\n\tuint16_t len;'
'\n\tchar *val;'
'\n}e_ble_tlv;')
pass
def _dt_trans_property_json_to_h_file(write_fd, _proterty_data):
if _dt_not_exist(_proterty_data):
return
_dt_write_macro_to_file(write_fd, 'INCLUDE_PROPERTY', '')
# all property id define, the tail of macro name corresponding to property id in json file
_dt_write_enum_to_file(write_fd, '// define property id', 'PROPERTY_ID', _dt_get_enum_list_from_ids(_proterty_data))
# define property id values, including size, length, limit ...
for property_id in _proterty_data:
if property_id[dt_config['JSON']['DEFINE']][dt_config['JSON']['TYPE']] == dt_config['JSON']['ENUM']:
enum_prefix, enum_val = _dt_get_enum_list_from_mapping(
property_id[dt_config['JSON']['DEFINE']][dt_config['JSON']['MAPPING']])
_dt_write_enum_to_file(write_fd, '// define property %s enum' % property_id[dt_config['JSON']['ID']],
'PROPERTY_' + property_id[dt_config['JSON']['ID']], enum_prefix, enum_val)
elif property_id[dt_config['JSON']['DEFINE']][dt_config['JSON']['TYPE']] == dt_config['JSON']['INT'] or \
property_id[dt_config['JSON']['DEFINE']][dt_config['JSON']['TYPE']] == dt_config['JSON']['FLOAT']:
_dt_write_newline_to_file(write_fd, '\n// define %s attributes' % property_id[dt_config['JSON']['ID']])
for k, v in property_id[dt_config['JSON']['DEFINE']].items():
if v != '' and k != dt_config['JSON']['TYPE'] and k != dt_config['JSON']['UNIT']:
_dt_write_macro_to_file(write_fd, 'PROPERTY_' + property_id[dt_config['JSON']['ID']] + '_' + k,
'(' + v + ')')
elif property_id[dt_config['JSON']['DEFINE']][dt_config['JSON']['TYPE']] == dt_config['JSON']['STRING']:
_dt_write_newline_to_file(write_fd, '\n// define %s length limit' % property_id[dt_config['JSON']['ID']])
for k, v in property_id[dt_config['JSON']['DEFINE']].items():
if v != '' and k != dt_config['JSON']['TYPE']:
_dt_write_macro_to_file(write_fd,
'PROPERTY_' + property_id[dt_config['JSON']['ID']] + '_LEN_' + k,
'(' + v + ')')
else:
pass
# define prototype of callback function
_dt_write_newline_to_file(write_fd, '\n// define property set handle return 0 if success, other is error\n'
'// sdk call the function that inform the server data to the device')
_dt_write_newline_to_file(write_fd, 'typedef int (*property_set_cb)(const char *data, uint16_t len);')
_dt_write_newline_to_file(write_fd,
'\n// define property get handle. return the data length obtained, -1 is error, 0 is no data\n'
'// sdk call the function fetch user data and send to the server, the data should wrapped by user '
'adn skd just transmit')
_dt_write_newline_to_file(write_fd, 'typedef int (*property_get_cb)(char *buf, uint16_t buf_len);')
_dt_write_newline_to_file(write_fd,
'\n// each property have a struct ble_property_t, make up a array named sg_ble_property_array')
_dt_write_newline_to_file(write_fd, 'typedef struct{'
'\n\tproperty_set_cb set_cb;\t//set callback'
'\n\tproperty_get_cb get_cb;\t//get callback'
'\n\tuint8_t authority;\t//property authority'
'\n\tuint8_t type;\t//data type'
'\n}ble_property_t;')
pass
def _dt_trans_event_json_to_h_file(write_fd, _event_data):
if _dt_not_exist(_event_data):
return
_dt_write_macro_to_file(write_fd, 'INCLUDE_EVENT', '')
# define event id
_dt_write_enum_to_file(write_fd, '// define event id', 'EVENT_ID', _dt_get_enum_list_from_ids(_event_data))
for event in _event_data:
# define param id of event
_dt_write_enum_to_file(write_fd, '// define param id for event %s' % event.get(dt_config['JSON']['ID']),
'EVENT_' + event.get(dt_config['JSON']['ID']) + '_PARAM_ID',
_dt_get_enum_list_from_ids(event.get(dt_config['JSON']['PARAMS'])))
# define param value of event
for param in event.get('params'):
if param[dt_config['JSON']['DEFINE']][dt_config['JSON']['TYPE']] == dt_config['JSON']['ENUM']:
enum_prefix, enum_val = _dt_get_enum_list_from_mapping(param[dt_config['JSON']['DEFINE']]['mapping'])
_dt_write_enum_to_file(write_fd, '// define enum for param %s' % param[dt_config['JSON']['ID']],
'EVEMT_' + event.get(dt_config['JSON']['ID']) + '_' + param[
dt_config['JSON']['ID']],
enum_prefix, enum_val)
elif param[dt_config['JSON']['DEFINE']][dt_config['JSON']['TYPE']] == dt_config['JSON']['INT'] or \
param[dt_config['JSON']['DEFINE']][dt_config['JSON']['TYPE']] == dt_config['JSON']['FLOAT']:
_dt_write_newline_to_file(write_fd, '\n// define param %s attributes' % param[dt_config['JSON']['ID']])
for k, v in param[dt_config['JSON']['DEFINE']].items():
if v != '' and k != dt_config['JSON']['TYPE'] and k != dt_config['JSON']['UNIT']:
_dt_write_macro_to_file(write_fd,
'EVENT_' + event.get(dt_config['JSON']['ID']) + '_' + param[
dt_config['JSON']['ID']] + '_' + k,
'(' + v + ')')
elif param[dt_config['JSON']['DEFINE']][dt_config['JSON']['TYPE']] == dt_config['JSON']['STRING']:
_dt_write_newline_to_file(write_fd, '\n// define range for param %s' % param[dt_config['JSON']['ID']])
for k, v in param[dt_config['JSON']['DEFINE']].items():
if v != '' and k != dt_config['JSON']['TYPE']:
_dt_write_macro_to_file(write_fd,
'EVENT_' + event.get(dt_config['JSON']['ID']) + '_' + param[
dt_config['JSON']['ID']] + '_LEN_' + k,
'(' + v + ')')
_dt_write_newline_to_file(write_fd,
'\n// define event get handle. return the data length obtained, -1 is error, 0 is no data\n'
'// sdk call the function fetch user data and send to the server, the data should wrapped by user '
'adn skd just transmit')
_dt_write_newline_to_file(write_fd, 'typedef int (*event_get_cb)(char *buf, uint16_t buf_len);')
_dt_write_newline_to_file(write_fd, '\n// each param have a struct ble_event_param, make up a array for the event')
_dt_write_newline_to_file(write_fd, 'typedef struct{'
'\n\tevent_get_cb get_cb;\t//get param data callback'
'\n\tuint8_t type;\t//param type'
'\n}ble_event_param;')
_dt_write_newline_to_file(write_fd, '\n// a array named sg_ble_event_array is composed by all the event array')
_dt_write_newline_to_file(write_fd, 'typedef struct{'
'\n\tble_event_param *event_array;\t//array of params data'
'\n\tuint8_t array_size;\t//array size'
'\n}ble_event_t;')
pass
def _dt_trans_action_json_to_h_file(write_fd, _action_data):
if _dt_not_exist(_action_data):
return
_dt_write_macro_to_file(write_fd, 'INCLUDE_ACTION', '')
# define action id
_dt_write_enum_to_file(write_fd, '// define action id', 'ACTION_ID', _dt_get_enum_list_from_ids(_action_data))
max_input_id, max_output_id = 0, 0
for action in _action_data:
# define action input id
_dt_write_enum_to_file(write_fd, '// define input id for action %s' % action.get(dt_config['JSON']['ID']),
'ACTION_' + action.get(dt_config['JSON']['ID']) + '_INPUT_ID',
_dt_get_enum_list_from_ids(action.get(dt_config['JSON']['INPUT'])))
_dt_write_enum_to_file(write_fd, '// define output id for action %s' % action.get(dt_config['JSON']['ID']),
'ACTION_' + action.get(dt_config['JSON']['ID']) + '_OUTPUT_ID',
_dt_get_enum_list_from_ids(action.get(dt_config['JSON']['OUTPUT'])))
max_input_id = max(len(_dt_get_enum_list_from_ids(action.get(dt_config['JSON']['INPUT']))), max_input_id)
max_output_id = max(len(_dt_get_enum_list_from_ids(action.get(dt_config['JSON']['OUTPUT']))), max_output_id)
# define input id values
for input_id in action.get('input'):
if input_id[dt_config['JSON']['DEFINE']][dt_config['JSON']['TYPE']] == dt_config['JSON']['ENUM']:
enum_prefix, enum_val = _dt_get_enum_list_from_mapping(
input_id[dt_config['JSON']['DEFINE']][dt_config['JSON']['MAPPING']])
_dt_write_enum_to_file(write_fd, '// define enum for input id %s' % input_id[dt_config['JSON']['ID']],
'ACTION_INPUT_' + action.get(dt_config['JSON']['ID']) + '_' + input_id[
dt_config['JSON']['ID']],
enum_prefix, enum_val)
elif input_id[dt_config['JSON']['DEFINE']][dt_config['JSON']['TYPE']] == dt_config['JSON']['INT'] or \
input_id[dt_config['JSON']['DEFINE']][dt_config['JSON']['TYPE']] == dt_config['JSON']['FLOAT']:
for k, v in input_id[dt_config['JSON']['DEFINE']].items():
if v != '' and k != dt_config['JSON']['TYPE'] and k != dt_config['JSON']['UNIT']:
_dt_write_macro_to_file(write_fd,
'ACTION_INPUT_' + action.get(dt_config['JSON']['ID']) + '_' + input_id[
dt_config['JSON']['ID']] + '_' + k,
'(' + v + ')')
elif input_id[dt_config['JSON']['DEFINE']][dt_config['JSON']['TYPE']] == dt_config['JSON']['STRING']:
_dt_write_newline_to_file(write_fd,
'\n// define input id %s attributes' % input_id[dt_config['JSON']['ID']])
for k, v in input_id[dt_config['JSON']['DEFINE']].items():
if v != '' and k != dt_config['JSON']['TYPE']:
_dt_write_macro_to_file(write_fd,
'ACTION_OUTPUT_' + action.get(dt_config['JSON']['ID']) + '_' + input_id[
dt_config['JSON']['ID']] + '_LEN_' + k,
'(' + v + ')')
else:
pass
for output in action.get('output'):
if output[dt_config['JSON']['DEFINE']][dt_config['JSON']['TYPE']] == dt_config['JSON']['ENUM']:
enum_prefix, enum_val = _dt_get_enum_list_from_mapping(
output[dt_config['JSON']['DEFINE']][dt_config['JSON']['MAPPING']])
_dt_write_enum_to_file(write_fd, '// define enum for output id %s' % output[dt_config['JSON']['ID']],
'ACTION_OUTPUT_' + action.get(dt_config['JSON']['ID']) + '_' + output[
dt_config['JSON']['ID']],
enum_prefix, enum_val)
elif output[dt_config['JSON']['DEFINE']][dt_config['JSON']['TYPE']] == dt_config['JSON']['INT'] or \
output[dt_config['JSON']['DEFINE']][dt_config['JSON']['TYPE']] == dt_config['JSON']['FLOAT']:
_dt_write_newline_to_file(write_fd,
'\n// define output id %s attributes' % output[dt_config['JSON']['ID']])
for k, v in output[dt_config['JSON']['DEFINE']].items():
if v != '' and k != dt_config['JSON']['TYPE'] and k != dt_config['JSON']['UNIT']:
_dt_write_macro_to_file(write_fd,
'ACTION_OUTPUT_' + action.get(dt_config['JSON']['ID']) + '_' + output[
dt_config['JSON']['ID']] + '_' + k,
'(' + v + ')')
elif output[dt_config['JSON']['DEFINE']][dt_config['JSON']['TYPE']] == dt_config['JSON']['STRING']:
_dt_write_newline_to_file(write_fd,
'\n// define output id %s attributes' % output[dt_config['JSON']['ID']])
for k, v in output[dt_config['JSON']['DEFINE']].items():
if v != '' and k != dt_config['JSON']['TYPE']:
_dt_write_macro_to_file(write_fd,
'ACTION_OUTPUT_' + action.get(dt_config['JSON']['ID']) + '_' + output[
dt_config['JSON']['ID']] + '_LEN_' + k,
'(' + v + ')')
_dt_write_newline_to_file(write_fd, '\n// define max input id and output id in all of input id and output id above')
_dt_write_macro_to_file(write_fd, 'ACTION_INPUT_ID_BUTT', str(max_input_id - 1))
_dt_write_macro_to_file(write_fd, 'ACTION_OUTPUT_ID_BUTT', str(max_output_id - 1))
_dt_write_newline_to_file(write_fd, '\n// define action input handle, return 0 is success, other is error.\n'
'// input_param_array carry the data from server, include input id, data length ,data val\n'
'// input_array_size means how many input id\n'
'// output_id_array filling with output id numbers that need obtained, sdk will traverse it and call the action_output_handle to obtained data')
_dt_write_newline_to_file(write_fd,
'typedef int (*action_input_handle)(e_ble_tlv *input_param_array, uint8_t input_array_size, uint8_t *output_id_array);')
_dt_write_newline_to_file(write_fd,
'\n// define action output handle, return length of the data, 0 is no data, -1 is error\n'
'// output_id means which id data should be obtained')
_dt_write_newline_to_file(write_fd,
'typedef int (*action_output_handle)(uint8_t output_id, char *buf, uint16_t buf_len);')
_dt_write_newline_to_file(write_fd,
'\n// each action have a struct ble_action_t, make up a array named sg_ble_action_array')
_dt_write_newline_to_file(write_fd, 'typedef struct{'
'\n\taction_input_handle input_cb;\t//handle input data'
'\n\taction_output_handle output_cb;\t// get output data in the callback'
'\n\tuint8_t *input_type_array;\t//type array for input id'
'\n\tuint8_t *output_type_array;\t//type array for output id'
'\n\tuint8_t input_id_size;\t//numbers of input id'
'\n\tuint8_t output_id_size;\t//numbers of output id'
'\n}ble_action_t;')
pass
def _dt_write_function_prototype(write_fd):
file_fd = open(os.path.join(script_path, 'dt_fixed_content', 'dt_ble_prototype'), 'r', encoding='UTF-8')
file_content = file_fd.read()
file_fd.close()
_dt_write_newline_to_file(write_fd, file_content)
pass
def _dt_generate_header_file(_json_data):
h_file = open(dt_config['FILE']['NAME_PREFIX'] + '.h', 'w', encoding='UTF-8')
_dt_write_newline_to_file(h_file, dt_config['FILE']['COPYRIGHT'])
_dt_write_newline_to_file(h_file, '#ifndef ' + dt_config['FILE']['NAME_PREFIX'].upper() + '_H_')
_dt_write_newline_to_file(h_file, '#define ' + dt_config['FILE']['NAME_PREFIX'].upper() + '_H_')
_dt_write_newline_to_file(h_file, '#ifdef __cplusplus\n' + 'extern "C"{\n#endif\n')
_dt_write_newline_to_file(h_file, '#include <stdint.h>\n')
_dt_write_public_header(h_file)
_dt_trans_property_json_to_h_file(h_file, _json_data.get(dt_config['JSON']['PROPERTY']))
_dt_trans_event_json_to_h_file(h_file, _json_data.get(dt_config['JSON']['EVENT']))
_dt_trans_action_json_to_h_file(h_file, _json_data.get(dt_config['JSON']['ACTION']))
_dt_write_function_prototype(h_file)
_dt_write_newline_to_file(h_file, '\n' + '#ifdef __cplusplus' + '\n' + '}' + '\n' + '#endif')
_dt_write_newline_to_file(h_file, '#endif ' + '//' + (dt_config['FILE']['NAME_PREFIX']).upper() + '_H_')
h_file.close()
pass
def _dt_get_property_function_name(property_id):
return 'ble_property_' + property_id.lower() + '_get'
def _dt_set_property_function_name(property_id):
return 'ble_property_' + property_id.lower() + '_set'
def _dt_get_property_mode(mode):
if mode == 'rw':
return 'BLE_QIOT_PROPERTY_AUTH_RW'
elif mode == 'r':
return 'BLE_QIOT_PROPERTY_AUTH_READ'
else:
print("invalid property mode")
pass
def _dt_get_type_by_str(type_str):
if type_str == dt_config['JSON']['BOOL']:
return 'BLE_QIOT_DATA_TYPE_BOOL'
elif type_str == dt_config['JSON']['INT']:
return 'BLE_QIOT_DATA_TYPE_INT'
elif type_str == dt_config['JSON']['STRING']:
return 'BLE_QIOT_DATA_TYPE_STRING'
elif type_str == dt_config['JSON']['FLOAT']:
return 'BLE_QIOT_DATA_TYPE_FLOAT'
elif type_str == dt_config['JSON']['ENUM']:
return 'BLE_QIOT_DATA_TYPE_ENUM'
elif type_str == dt_config['JSON']['TIME']:
return 'BLE_QIOT_DATA_TYPE_TIME'
else:
print('invalid type string')
pass
def _dt_get_ret_val_by_type(data_type):
if data_type == dt_config['JSON']['STRING']:
return 'buf_len'
elif data_type == dt_config['JSON']['INT']:
return 'sizeof(uint32_t)'
elif data_type == dt_config['JSON']['ENUM']:
return 'sizeof(uint16_t)'
elif data_type == dt_config['JSON']['BOOL']:
return 'sizeof(uint8_t)'
elif data_type == dt_config['JSON']['FLOAT']:
return 'sizeof(float)'
elif data_type == dt_config['JSON']['TIME']:
return 'sizeof(uint32_t)'
else:
print('invalid data type')
def _dt_get_function_param_by_type(data_type):
return '(char *data, uint16_t buf_len)'
def _dt_trans_property_json_to_c_file(write_fd, _proterty_data):
if _dt_not_exist(_proterty_data):
return
# define property set/get function
for property_id in _proterty_data:
_dt_write_newline_to_file(write_fd,
'static int ' + _dt_set_property_function_name(
property_id.get(dt_config['JSON']['ID'])) +
'(const char *data, uint16_t len)\n{\n\treturn 0;\n}\n')
_dt_write_newline_to_file(write_fd,
'static int ' + _dt_get_property_function_name(
property_id.get(dt_config['JSON']['ID'])) +
'%s\n{\n\treturn %s;\n}\n' %
(_dt_get_function_param_by_type(
property_id.get(dt_config['JSON']['DEFINE']).get(dt_config['JSON']['TYPE'])),
_dt_get_ret_val_by_type(
property_id.get(dt_config['JSON']['DEFINE']).get(dt_config['JSON']['TYPE']))))
# define property array
_dt_write_newline_to_file(write_fd, 'static ble_property_t sg_ble_property_array[BLE_QIOT_PROPERTY_ID_BUTT] = {')
for property_id in _proterty_data:
_dt_write_newline_to_file(write_fd, '\t{%-30s %-30s %-20s %-20s},' %
(_dt_set_property_function_name(property_id.get(dt_config['JSON']['ID'])) + ',',
_dt_get_property_function_name(property_id.get(dt_config['JSON']['ID'])) + ',',
_dt_get_property_mode(property_id.get(dt_config['JSON']['MODE'])) + ',',
_dt_get_type_by_str(
property_id.get(dt_config['JSON']['DEFINE']).get(dt_config['JSON']['TYPE']))
))
_dt_write_newline_to_file(write_fd, '};\n')
dt_property_file = open(os.path.join(script_path, 'dt_fixed_content', 'dt_ble_property'), 'r', encoding='UTF-8')
dt_property_content = dt_property_file.read()
dt_property_file.close()
# write operation to file
_dt_write_newline_to_file(write_fd, dt_property_content)
pass
def _dt_trans_event_json_to_c_file(write_fd, _evnet_data):
if _dt_not_exist(_evnet_data):
return
for event in _evnet_data:
# define event get function
for param in event.get('params'):
_dt_write_newline_to_file(write_fd,
'static int ' + 'ble_event_get_' + event.get(dt_config['JSON']['ID']).lower() +
'_' + param.get(dt_config['JSON']['ID']).lower() + '%s\n{\n\treturn %s;\n}\n' %
(_dt_get_function_param_by_type(
param.get(dt_config['JSON']['DEFINE']).get(dt_config['JSON']['TYPE'])),
_dt_get_ret_val_by_type(
param.get(dt_config['JSON']['DEFINE']).get(dt_config['JSON']['TYPE']))))
# define param array
_dt_write_newline_to_file(write_fd, 'static ble_event_param sg_ble_event_%s_array[%s] = {' %
(event.get(dt_config['JSON']['ID']).lower(),
dt_config['FILE']['ENUM_PREFIX'] + 'EVENT_' +
event.get(dt_config['JSON']['ID']).upper() + '_PARAM_ID_BUTT'))
for param in event.get('params'):
_dt_write_newline_to_file(write_fd, '\t{%-32s %-20s},' % (
'ble_event_get_' + event.get(dt_config['JSON']['ID']).lower() + '_' + param.get(
dt_config['JSON']['ID']).lower() + ', ',
_dt_get_type_by_str(param.get(dt_config['JSON']['DEFINE']).get(dt_config['JSON']['TYPE']))))
_dt_write_newline_to_file(write_fd, '};\n')
# define event array
_dt_write_newline_to_file(write_fd, 'static ble_event_t sg_ble_event_array[BLE_QIOT_EVENT_ID_BUTT] = {')
for event in _evnet_data:
_dt_write_newline_to_file(write_fd, '\t{%-32s %-32s},' % (
'sg_ble_event_' + event.get(dt_config['JSON']['ID']).lower() + '_array,',
'sizeof(sg_ble_event_' + event.get(dt_config['JSON']['ID']).lower() + '_array) / sizeof(ble_event_param)'))
_dt_write_newline_to_file(write_fd, '};\n')
dt_event_file = open(os.path.join(script_path, 'dt_fixed_content', 'dt_ble_event'), 'r', encoding='UTF-8')
dt_event_content = dt_event_file.read()
dt_event_file.close()
# write operation to file
_dt_write_newline_to_file(write_fd, dt_event_content)
pass
def _dt_trans_action_json_to_c_file(write_fd, _action_data):
if _dt_not_exist(_action_data):
return
for idx, action in enumerate(_action_data):
# define action input and output callback
_dt_write_newline_to_file(write_fd,
'static int ' + 'ble_action_handle_' + action.get(
dt_config['JSON']['ID']).lower() + '_input_cb' +
'(e_ble_tlv *input_param_array, uint8_t input_array_size, uint8_t *output_id_array)\n'
'{\n\treturn 0;\n}\n')
_dt_write_newline_to_file(write_fd,
'static int ' + 'ble_action_handle_' + action.get(
dt_config['JSON']['ID']).lower() + '_output_cb' +
'(uint8_t output_id, char *buf, uint16_t buf_len)\n'
'{\n\treturn buf_len;\n}\n')
# define type array of input id
_dt_write_newline_to_file(write_fd,
'static uint8_t ' + 'sg_ble_action_%s_input_type_array[%s] = {' %
(action.get(dt_config['JSON']['ID']).lower(),
dt_config['FILE']['ENUM_PREFIX'] + 'ACTION_' +
action.get(dt_config['JSON']['ID']).upper() + '_INPUT_ID_BUTT'))
for input_id in action.get('input'):
_dt_write_newline_to_file(write_fd,
'\t' + _dt_get_type_by_str(input_id.get(dt_config['JSON']['DEFINE']).get(
dt_config['JSON']['TYPE'])) + ',')
_dt_write_newline_to_file(write_fd, '};\n')
# define type array of output id
_dt_write_newline_to_file(write_fd,
'static uint8_t ' + 'sg_ble_action_%s_output_type_array[%s] = {' % (
action.get(dt_config['JSON']['ID']).lower(),
dt_config['FILE']['ENUM_PREFIX'] + 'ACTION_' + action.get(
dt_config['JSON']['ID']).upper() + '_OUTPUT_ID_BUTT'))
for input_id in action.get('output'):
_dt_write_newline_to_file(write_fd,
'\t' + _dt_get_type_by_str(input_id.get(dt_config['JSON']['DEFINE']).get(
dt_config['JSON']['TYPE'])) + ',')
_dt_write_newline_to_file(write_fd, '};\n')
# define action array
_dt_write_newline_to_file(write_fd, 'static ble_action_t ' + 'sg_ble_action_array[BLE_QIOT_ACTION_ID_BUTT] = {')
for action in _action_data:
_dt_write_newline_to_file(write_fd,
'\t{ble_action_handle_%s_input_cb, ble_action_handle_%s_output_cb, \n'
'\t\tsg_ble_action_%s_input_type_array, sg_ble_action_%s_output_type_array, \n'
'\t\tsizeof(sg_ble_action_%s_input_type_array) / sizeof(uint8_t), \n'
'\t\tsizeof(sg_ble_action_%s_output_type_array) / sizeof(uint8_t)},' %
(action.get(dt_config['JSON']['ID']).lower(),
action.get(dt_config['JSON']['ID']).lower(),
action.get(dt_config['JSON']['ID']).lower(),
action.get(dt_config['JSON']['ID']).lower(),
action.get(dt_config['JSON']['ID']).lower(),
action.get(dt_config['JSON']['ID']).lower()))
_dt_write_newline_to_file(write_fd, '};\n')
dt_action_file = open(os.path.join(script_path, 'dt_fixed_content', 'dt_ble_action'), 'r', encoding='UTF-8')
dt_action_content = dt_action_file.read()
dt_action_file.close()
# write operation to file
_dt_write_newline_to_file(write_fd, dt_action_content)
pass
def _dt_generate_c_file(_json_data):
c_file = open(dt_config['FILE']['NAME_PREFIX'] + '.c', 'w', encoding='UTF-8')
_dt_write_newline_to_file(c_file, dt_config['FILE']['COPYRIGHT'])
_dt_write_newline_to_file(c_file, '#ifdef __cplusplus\nextern "C" {\n#endif\n')
_dt_write_newline_to_file(c_file, '#include "ble_qiot_template.h"\n')
_dt_write_newline_to_file(c_file, '#include <stdio.h>')
_dt_write_newline_to_file(c_file, '#include <stdbool.h>')
_dt_write_newline_to_file(c_file, '#include <string.h>\n')
_dt_write_newline_to_file(c_file, '#include "ble_qiot_export.h"')
_dt_write_newline_to_file(c_file, '#include "ble_qiot_common.h"')
_dt_write_newline_to_file(c_file, '#include "ble_qiot_param_check.h"\n')
_dt_trans_property_json_to_c_file(c_file, _json_data.get(dt_config['JSON']['PROPERTY']))
_dt_trans_event_json_to_c_file(c_file, _json_data.get(dt_config['JSON']['EVENT']))
_dt_trans_action_json_to_c_file(c_file, _json_data.get(dt_config['JSON']['ACTION']))
_dt_write_newline_to_file(c_file, '\n#ifdef __cplusplus\n}\n#endif')
pass
if __name__ == "__main__":
if len(sys.argv) != 2:
print('Usage: python3 %s <json_file>' % sys.argv[0])
else:
print("reading json file start")
json_data = _dt_get_json_from_file(sys.argv[1])
print("reading json file end")
print("generate header file start")
_dt_generate_header_file(json_data)
print("generate header file end")
print("generate source file start")
_dt_generate_c_file(json_data)
print("generate source file end")
pass

View File

@@ -0,0 +1,349 @@
/*
* 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_llsync_data.h"
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include "ble_qiot_export.h"
#include "ble_qiot_import.h"
#include "ble_qiot_common.h"
#include "ble_qiot_llsync_event.h"
#include "ble_qiot_utils_base64.h"
#include "ble_qiot_log.h"
#include "ble_qiot_param_check.h"
#include "ble_qiot_service.h"
#include "ble_qiot_template.h"
#define BLE_LLDATA_MAX_INPUT_ID 8
#define BLE_LLDATA_MAX_OUTPUT_ID 8
static int ble_lldata_parse_tlv(const char *buf, int buf_len, e_ble_tlv *tlv)
{
int ret_len = 0;
uint16_t string_len = 0;
tlv->type = BLE_QIOT_PARSE_TLV_HEAD_TYPE(buf[0]);
if (tlv->type >= BLE_QIOT_DATA_TYPE_BUTT) {
ble_qiot_log_e("invalid tlv type %d", tlv->type);
return -1;
}
tlv->id = BLE_QIOT_PARSE_TLV_HEAD_ID(buf[0]);
ret_len++;
switch (tlv->type) {
case BLE_QIOT_DATA_TYPE_BOOL:
tlv->len = 1;
tlv->val = (char *)buf + ret_len;
ret_len += 1;
break;
case BLE_QIOT_DATA_TYPE_ENUM:
tlv->len = 2;
tlv->val = (char *)buf + ret_len;
ret_len += 2;
break;
case BLE_QIOT_DATA_TYPE_INT:
case BLE_QIOT_DATA_TYPE_FLOAT:
case BLE_QIOT_DATA_TYPE_TIME:
tlv->len = 4;
tlv->val = (char *)buf + ret_len;
ret_len += 4;
break;
case BLE_QIOT_DATA_TYPE_STRING:
if (buf_len < 3) {
ble_qiot_log_e("buf length invalid");
return -1;
}
memcpy(&string_len, &buf[ret_len], sizeof(int16_t));
tlv->len = NTOHS(string_len);
ret_len += 2;
tlv->val = (char *)buf + ret_len;
ret_len += tlv->len;
break;
default:
break;
}
ble_qiot_log_d("type %d, id %d, len %d", tlv->type, tlv->id, tlv->len);
return ret_len;
}
static ble_qiot_ret_status_t ble_lldata_property_data_handle(bool is_request, const char *in_buf, int buf_len)
{
#ifdef BLE_QIOT_INCLUDE_PROPERTY
uint16_t parse_len = 0;
uint16_t ret_len = 0;
e_ble_tlv tlv;
int handle_ret = BLE_QIOT_REPLY_SUCCESS;
ble_qiot_ret_status_t inform_ret = BLE_QIOT_RS_OK;
while (parse_len < buf_len) {
memset(&tlv, 0, sizeof(e_ble_tlv));
ret_len = ble_lldata_parse_tlv(in_buf + parse_len, buf_len - parse_len, &tlv);
parse_len += ret_len;
if (parse_len > buf_len) {
ble_qiot_log_e("parse tlv failed");
handle_ret = BLE_QIOT_REPLY_DATA_ERR;
break;
}
if (BLE_QIOT_RS_OK != ble_user_property_set_data(&tlv)) {
ble_qiot_log_e("user handle property error, id %d, type %d, len %d", tlv.id, tlv.type, tlv.len);
handle_ret = BLE_QIOT_REPLY_FAIL;
break;
}
}
if (is_request) {
inform_ret =
ble_event_notify(BLE_QIOT_EVENT_UP_CONTROL_REPLY, NULL, 0, (const char *)&handle_ret, sizeof(uint8_t));
return (BLE_QIOT_REPLY_SUCCESS == handle_ret) ? inform_ret : BLE_QIOT_RS_ERR;
} else {
return (BLE_QIOT_REPLY_SUCCESS == handle_ret) ? BLE_QIOT_RS_OK : BLE_QIOT_RS_ERR;
}
#else
ble_qiot_log_e("llsync property not support");
return BLE_QIOT_RS_OK;
#endif
}
#ifdef BLE_QIOT_INCLUDE_PROPERTY
ble_qiot_ret_status_t ble_user_property_get_report_data(void)
{
uint8_t property_id = 0;
uint8_t property_type = 0;
int property_len = 0;
uint8_t data_buf[BLE_QIOT_EVENT_MAX_SIZE] = {0};
uint16_t data_len = 0;
uint16_t string_len = 0;
ble_qiot_log_d("property report");
for (property_id = 0; property_id < BLE_QIOT_PROPERTY_ID_BUTT; property_id++) {
property_type = ble_get_property_type_by_id(property_id);
if (property_type == BLE_QIOT_DATA_TYPE_BUTT) {
ble_qiot_log_e("property id %d type %d invalid", property_id, property_type);
return BLE_QIOT_RS_ERR;
}
data_buf[data_len++] = BLE_QIOT_PACKAGE_TLV_HEAD(property_type, property_id);
if (BLE_QIOT_DATA_TYPE_STRING == property_type) {
// reserved 2 bytes for string length
property_len = ble_user_property_get_data_by_id(property_id, (char *)data_buf + data_len + 2,
sizeof(data_buf) - data_len - 2);
} else {
property_len =
ble_user_property_get_data_by_id(property_id, (char *)data_buf + data_len, sizeof(data_buf) - data_len);
}
if (property_len < 0) {
ble_qiot_log_e("too long data, property id %d, data length %d", property_id, data_len);
return BLE_QIOT_RS_ERR;
} else if (property_len == 0) {
// no data to post
data_len--;
data_buf[data_len] = '0';
ble_qiot_log_d("property id %d no data to post", property_id);
} else {
if (BLE_QIOT_DATA_TYPE_STRING == property_type) {
string_len = HTONS(property_len);
memcpy(data_buf + data_len, &string_len, sizeof(uint16_t));
data_len += sizeof(uint16_t);
}
data_len += property_len;
}
}
// ble_qiot_log_hex(BLE_QIOT_LOG_LEVEL_INFO, "user data", data_buf, data_len);
return ble_event_notify(BLE_QIOT_EVENT_UP_PROPERTY_REPORT, NULL, 0, (const char *)data_buf, data_len);
}
#endif
// default method is control
ble_qiot_ret_status_t ble_lldata_property_request_handle(const char *in_buf, int buf_len)
{
return ble_lldata_property_data_handle(true, in_buf, buf_len);
}
static ble_qiot_ret_status_t ble_lldata_property_report_reply(const char *in_buf, int buf_len)
{
#ifdef BLE_QIOT_INCLUDE_PROPERTY
int ret_code = 0;
ret_code = ble_user_property_report_reply_handle(in_buf[0]);
if (ret_code) {
ble_qiot_log_e("ble_user_property_report_reply_handle error, ret %d", ret_code);
return BLE_QIOT_RS_ERR;
}
return BLE_QIOT_RS_OK;
#else
ble_qiot_log_e("llsync property not support");
return BLE_QIOT_RS_OK;
#endif
}
static ble_qiot_ret_status_t ble_lldata_property_get_status_reply(const char *in_buf, int buf_len)
{
#ifdef BLE_QIOT_INCLUDE_PROPERTY
uint8_t result = 0;
uint16_t reply_len = 0;
result = in_buf[0];
memcpy(&reply_len, &in_buf[1], sizeof(uint16_t));
reply_len = NTOHS(reply_len);
ble_qiot_log_d("get status result %d, data len %d", result, reply_len);
if (BLE_QIOT_REPLY_SUCCESS == result) {
return ble_lldata_property_data_handle(false, in_buf + 3, reply_len);
} else {
ble_qiot_log_e("get status failed, result %d", result);
return BLE_QIOT_RS_ERR;
}
#else
ble_qiot_log_e("llsync property not support");
return BLE_QIOT_RS_OK;
#endif
}
// handle reply from remote
ble_qiot_ret_status_t ble_lldata_property_reply_handle(uint8_t type, const char *in_buf, int buf_len)
{
switch (type) {
case BLE_QIOT_DATA_DOWN_REPORT_REPLY:
return ble_lldata_property_report_reply(in_buf, buf_len);
case BLE_QIOT_DATA_DOWN_GET_STATUS_REPLY:
return ble_lldata_property_get_status_reply(in_buf, buf_len);
default:
ble_qiot_log_e("invalid property reply type");
break;
}
return BLE_QIOT_RS_OK;
}
ble_qiot_ret_status_t ble_lldata_event_handle(uint8_t id, const char *in_buf, int len)
{
#ifdef BLE_QIOT_INCLUDE_EVENT
int ret_code = 0;
ret_code = ble_user_event_reply_handle(id, in_buf[0]);
if (ret_code) {
ble_qiot_log_e("ble_user_event_reply_handle error, ret %d", ret_code);
return BLE_QIOT_RS_ERR;
}
#else
ble_qiot_log_e("llsync event not support");
#endif
return BLE_QIOT_RS_OK;
}
ble_qiot_ret_status_t ble_lldata_action_handle(uint8_t action_id, const char *in_buf, int len)
{
#ifdef BLE_QIOT_INCLUDE_ACTION
POINTER_SANITY_CHECK(in_buf, BLE_QIOT_RS_ERR_PARA);
uint16_t parse_len = 0;
uint8_t tlv_index = 0;
int ret_len = 0;
e_ble_tlv tlv[BLE_QIOT_ACTION_INPUT_ID_BUTT] = {0};
int handle_ret = BLE_QIOT_REPLY_SUCCESS;
uint8_t output_flag_array[BLE_QIOT_ACTION_OUTPUT_ID_BUTT] = {0};
uint8_t output_id = 0;
uint8_t output_type = 0;
uint8_t data_buf[BLE_QIOT_EVENT_MAX_SIZE] = {0};
uint16_t data_len = 0;
int output_param_len = 0;
uint16_t string_len = 0;
uint8_t header_buf[2] = {0};
ble_qiot_log_d("action %d", action_id);
while (parse_len < len) {
if (tlv_index >= BLE_QIOT_ACTION_INPUT_ID_BUTT) {
ble_qiot_log_e("invalid tlv index %d", tlv_index);
handle_ret = BLE_QIOT_REPLY_DATA_ERR;
goto end;
}
ret_len = ble_lldata_parse_tlv(in_buf + parse_len, len - parse_len, &tlv[tlv_index]);
if (-1 == ret_len) {
handle_ret = BLE_QIOT_REPLY_DATA_ERR;
goto end;
}
parse_len += ret_len;
tlv_index++;
if (parse_len > len) {
ble_qiot_log_e("parse tlv failed");
handle_ret = BLE_QIOT_REPLY_DATA_ERR;
goto end;
}
}
if (0 != ble_action_user_handle_input_param(action_id, tlv, tlv_index, output_flag_array)) {
ble_qiot_log_e("handle input failed, id %d", action_id);
handle_ret = BLE_QIOT_REPLY_FAIL;
goto end;
}
for (output_id = 0; output_id < BLE_QIOT_ACTION_OUTPUT_ID_BUTT; output_id++) {
if (output_flag_array[output_id]) {
output_type = ble_action_get_output_type_by_id(action_id, output_id);
if (output_type == BLE_QIOT_DATA_TYPE_BUTT) {
ble_qiot_log_e("invalid type, action id %d, output id %d", action_id, output_id);
handle_ret = BLE_QIOT_REPLY_FAIL;
goto end;
}
data_buf[data_len++] = BLE_QIOT_PACKAGE_TLV_HEAD(output_type, output_id);
if (BLE_QIOT_DATA_TYPE_STRING == output_type) {
output_param_len = ble_action_user_handle_output_param(
action_id, output_id, (char *)data_buf + data_len + 2, sizeof(data_buf) - data_len - 2);
} else {
output_param_len = ble_action_user_handle_output_param(
action_id, output_id, (char *)data_buf + data_len, sizeof(data_buf) - data_len);
}
if (output_param_len < 0) {
ble_qiot_log_e("too long data, action id %d, data length %d", action_id, data_len);
handle_ret = BLE_QIOT_REPLY_FAIL;
goto end;
} else if (output_param_len == 0) {
// no data to post
data_len--;
data_buf[data_len] = '0';
ble_qiot_log_d("output id %d no data to post", output_id);
} else {
if (BLE_QIOT_DATA_TYPE_STRING == output_type) {
string_len = HTONS(output_param_len);
memcpy(data_buf + data_len, &string_len, sizeof(uint16_t));
data_len += sizeof(uint16_t);
}
data_len += output_param_len;
}
}
}
// ble_qiot_log_hex(BLE_QIOT_LOG_LEVEL_INFO, "user data", data_buf, data_len);
header_buf[0] = BLE_QIOT_REPLY_SUCCESS;
header_buf[1] = action_id;
return ble_event_notify(BLE_QIOT_EVENT_UP_ACTION_REPLY, header_buf, sizeof(header_buf), (const char *)data_buf,
data_len);
end:
ble_event_notify(BLE_QIOT_EVENT_UP_ACTION_REPLY, NULL, 0, (const char *)&handle_ret, sizeof(uint8_t));
return BLE_QIOT_RS_ERR;
#else
ble_qiot_log_e("llsync action not support");
return BLE_QIOT_RS_ERR;
#endif
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,357 @@
/*
* 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_llsync_device.h"
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "ble_qiot_common.h"
#include "ble_qiot_config.h"
#include "ble_qiot_export.h"
#include "ble_qiot_hmac.h"
#include "ble_qiot_import.h"
#include "ble_qiot_log.h"
#include "ble_qiot_param_check.h"
#include "ble_qiot_utils_base64.h"
#include "ble_qiot_md5.h"
#define BLE_GET_EXPIRATION_TIME(_cur_time) ((_cur_time) + BLE_EXPIRATION_TIME)
static ble_core_data sg_core_data; // ble data storage in flash
static ble_device_info sg_device_info; // device info storage in flash
static e_llsync_bind_state sg_llsync_bind_state; // llsync bind state in used
static e_llsync_connection_state sg_llsync_connection_state; // llsync connection state in used
static e_ble_connection_state sg_ble_connection_state; // ble connection state in used
static int memchk(const uint8_t *buf, int len)
{
int i = 0;
for (i = 0; i < len; i++) {
if (buf[i] != 0xFF) {
return 1;
}
}
return 0;
}
ble_qiot_ret_status_t ble_init_flash_data(void)
{
if (sizeof(sg_core_data) !=
ble_read_flash(BLE_QIOT_RECORD_FLASH_ADDR, (char *)&sg_core_data, sizeof(sg_core_data))) {
ble_qiot_log_e("read flash error");
return BLE_QIOT_RS_ERR_FLASH;
}
if (0 == memchk((const uint8_t *)&sg_core_data, sizeof(sg_core_data))) {
memset(&sg_core_data, 0, sizeof(sg_core_data));
}
if (0 != ble_get_mac(sg_device_info.mac)) {
ble_qiot_log_e("get mac error");
return BLE_QIOT_RS_ERR_FLASH;
}
if (0 != ble_get_product_id(sg_device_info.product_id)) {
ble_qiot_log_e("get product id error");
return BLE_QIOT_RS_ERR_FLASH;
}
if (0 != ble_get_psk(sg_device_info.psk)) {
ble_qiot_log_e("get secret key error");
return BLE_QIOT_RS_ERR_FLASH;
}
if (0 == ble_get_device_name(sg_device_info.device_name)) {
ble_qiot_log_e("get device name error");
return BLE_QIOT_RS_ERR_FLASH;
}
llsync_bind_state_set((e_llsync_bind_state)sg_core_data.bind_state);
ble_qiot_log_hex(BLE_QIOT_LOG_LEVEL_INFO, "core_data", (char *)&sg_core_data, sizeof(sg_core_data));
ble_qiot_log_hex(BLE_QIOT_LOG_LEVEL_INFO, "device_info", (char *)&sg_device_info, sizeof(sg_device_info));
return BLE_QIOT_RS_OK;
}
static ble_qiot_ret_status_t ble_write_core_data(ble_core_data *core_data)
{
memcpy(&sg_core_data, core_data, sizeof(ble_core_data));
if (sizeof(ble_core_data) !=
ble_write_flash(BLE_QIOT_RECORD_FLASH_ADDR, (char *)&sg_core_data, sizeof(ble_core_data))) {
ble_qiot_log_e("write core failed");
return BLE_QIOT_RS_ERR_FLASH;
}
return BLE_QIOT_RS_OK;
}
void llsync_bind_state_set(e_llsync_bind_state new_state)
{
ble_qiot_log_d("bind state: %d ---> %d", sg_llsync_bind_state, new_state);
sg_llsync_bind_state = new_state;
}
e_llsync_bind_state llsync_bind_state_get(void)
{
return sg_llsync_bind_state;
}
void llsync_connection_state_set(e_llsync_connection_state new_state)
{
ble_qiot_log_d("connection state: %d ---> %d", sg_llsync_connection_state, new_state);
sg_llsync_connection_state = new_state;
}
e_llsync_connection_state llsync_connection_state_get(void)
{
return sg_llsync_connection_state;
}
void ble_connection_state_set(e_ble_connection_state new_state)
{
sg_ble_connection_state = new_state;
}
e_ble_connection_state ble_connection_state_get(void)
{
return sg_ble_connection_state;
}
bool ble_is_connected(void)
{
return sg_ble_connection_state == E_BLE_CONNECTED;
}
bool llsync_is_connected(void)
{
return sg_llsync_connection_state == E_LLSYNC_CONNECTED;
}
// [1byte bind state] + [6 bytes mac] + [8bytes identify string]/[10 bytes product id]
int ble_get_my_broadcast_data(char *out_buf, int buf_len)
{
POINTER_SANITY_CHECK(out_buf, BLE_QIOT_RS_ERR_PARA);
BUFF_LEN_SANITY_CHECK(buf_len, BLE_BIND_IDENTIFY_STR_LEN + BLE_QIOT_MAC_LEN + 1, BLE_QIOT_RS_ERR_PARA);
int ret_len = 0;
out_buf[ret_len] = sg_llsync_bind_state & LLSYNC_BIND_STATE_MASK;
out_buf[ret_len] |= BLE_QIOT_LLSYNC_PROTOCOL_VERSION << 4;
ret_len++;
if (E_LLSYNC_BIND_SUCC == (sg_llsync_bind_state & LLSYNC_BIND_STATE_MASK)) {
uint8_t md5_in_buf[128] = {0};
uint8_t md5_in_len = 0;
uint8_t md5_out_buf[MD5_DIGEST_SIZE] = {0};
// 1 bytes state + 8 bytes device identify_str + 8 bytes identify_str
memcpy((char *)md5_in_buf, sg_device_info.product_id, sizeof(sg_device_info.product_id));
md5_in_len += sizeof(sg_device_info.product_id);
memcpy((char *)md5_in_buf + md5_in_len, sg_device_info.device_name, strlen(sg_device_info.device_name));
md5_in_len += strlen(sg_device_info.device_name);
utils_md5(md5_in_buf, md5_in_len, md5_out_buf);
for (int i = 0; i < MD5_DIGEST_SIZE / 2; i++) {
out_buf[i + ret_len] = md5_out_buf[i] ^ md5_out_buf[i + MD5_DIGEST_SIZE / 2];
}
ret_len += MD5_DIGEST_SIZE / 2;
memcpy(out_buf + ret_len, sg_core_data.identify_str, sizeof(sg_core_data.identify_str));
ret_len += sizeof(sg_core_data.identify_str);
} else {
// 1 bytes state + 6 bytes mac + 10 bytes product id
memcpy(out_buf + ret_len, sg_device_info.mac, BLE_QIOT_MAC_LEN);
ret_len += BLE_QIOT_MAC_LEN;
memcpy(out_buf + ret_len, sg_device_info.product_id, sizeof(sg_device_info.product_id));
ret_len += sizeof(sg_device_info.product_id);
}
ble_qiot_log_hex(BLE_QIOT_LOG_LEVEL_INFO, "broadcast", out_buf, ret_len);
return ret_len;
}
int ble_bind_get_authcode(const char *bind_data, uint16_t data_len, char *out_buf, uint16_t buf_len)
{
POINTER_SANITY_CHECK(bind_data, BLE_QIOT_RS_ERR_PARA);
BUFF_LEN_SANITY_CHECK(data_len, (int32_t)sizeof(ble_bind_data), BLE_QIOT_RS_ERR_PARA);
POINTER_SANITY_CHECK(out_buf, BLE_QIOT_RS_ERR_PARA);
BUFF_LEN_SANITY_CHECK(buf_len, SHA1_DIGEST_SIZE + BLE_QIOT_DEVICE_NAME_LEN, BLE_QIOT_RS_ERR_PARA);
char out_sign[SHA1_DIGEST_SIZE] = {0};
char sign_info[80] = {0};
int sign_info_len = 0;
int time_expiration = 0;
int nonce = 0;
int ret_len = 0;
uint8_t secret[BLE_QIOT_PSK_LEN / 4 * 3] = {0};
int secret_len = 0;
// if the pointer "char *bind_data" is not aligned with 4 byte, in some cpu convert it to
// pointer "ble_bind_data *" work correctly, but some cpu will get wrong value, or cause
// other "Unexpected Error". Here copy it to a local variable make sure aligned with 4 byte.
ble_bind_data bind_data_aligned;
memcpy(&bind_data_aligned, bind_data, sizeof(ble_bind_data));
nonce = NTOHL(bind_data_aligned.nonce);
time_expiration = BLE_GET_EXPIRATION_TIME(NTOHL(bind_data_aligned.timestamp));
// [10 bytes product_id] + [x bytes device name] + ';' + [4 bytes nonce] + ';' + [4 bytes timestamp]
memcpy(sign_info, sg_device_info.product_id, sizeof(sg_device_info.product_id));
sign_info_len += sizeof(sg_device_info.product_id);
memcpy(sign_info + sign_info_len, sg_device_info.device_name, strlen(sg_device_info.device_name));
sign_info_len += strlen(sg_device_info.device_name);
snprintf(sign_info + sign_info_len, sizeof(sign_info) - sign_info_len, ";%u", nonce);
sign_info_len += strlen(sign_info + sign_info_len);
snprintf(sign_info + sign_info_len, sizeof(sign_info) - sign_info_len, ";%u", time_expiration);
sign_info_len += strlen(sign_info + sign_info_len);
qcloud_iot_utils_base64decode(secret, sizeof(secret), (size_t *)&secret_len,
(const unsigned char *)sg_device_info.psk, sizeof(sg_device_info.psk));
ble_qiot_log_hex(BLE_QIOT_LOG_LEVEL_INFO, "bind sign in", sign_info, sign_info_len);
utils_hmac_sha1((const char *)sign_info, sign_info_len, out_sign, (const char *)secret, secret_len);
ble_qiot_log_hex(BLE_QIOT_LOG_LEVEL_INFO, "bind sign out", out_sign, sizeof(out_sign));
// return [SHA1_DIGEST_SIZE bytes sign] + [x bytes device_name]
memset(out_buf, 0, buf_len);
memcpy(out_buf, out_sign, SHA1_DIGEST_SIZE);
ret_len += SHA1_DIGEST_SIZE;
memcpy(out_buf + ret_len, sg_device_info.device_name, strlen(sg_device_info.device_name));
ret_len += strlen(sg_device_info.device_name);
ble_qiot_log_hex(BLE_QIOT_LOG_LEVEL_INFO, "bind auth code", out_buf, ret_len);
return ret_len;
}
ble_qiot_ret_status_t ble_bind_write_result(const char *result, uint16_t len)
{
POINTER_SANITY_CHECK(result, BLE_QIOT_RS_ERR_PARA);
BUFF_LEN_SANITY_CHECK(len, (int32_t)sizeof(ble_core_data), BLE_QIOT_RS_ERR_PARA);
ble_core_data *bind_result = (ble_core_data *)result;
llsync_bind_state_set((e_llsync_bind_state)bind_result->bind_state);
return ble_write_core_data(bind_result);
}
ble_qiot_ret_status_t ble_unbind_write_result(void)
{
ble_core_data bind_result;
llsync_connection_state_set(E_LLSYNC_DISCONNECTED);
llsync_bind_state_set(E_LLSYNC_BIND_IDLE);
memset(&bind_result, 0, sizeof(bind_result));
return ble_write_core_data(&bind_result);
}
int ble_conn_get_authcode(const char *conn_data, uint16_t data_len, char *out_buf, uint16_t buf_len)
{
POINTER_SANITY_CHECK(conn_data, BLE_QIOT_RS_ERR_PARA);
BUFF_LEN_SANITY_CHECK(data_len, (int32_t)sizeof(ble_conn_data), BLE_QIOT_RS_ERR_PARA);
POINTER_SANITY_CHECK(out_buf, BLE_QIOT_RS_ERR_PARA);
BUFF_LEN_SANITY_CHECK(buf_len, SHA1_DIGEST_SIZE + BLE_QIOT_DEVICE_NAME_LEN, BLE_QIOT_RS_ERR_PARA);
char sign_info[64] = {0};
char out_sign[SHA1_DIGEST_SIZE] = {0};
int sign_info_len = 0;
int timestamp = 0;
int ret_len = 0;
// if the pointer "char *bind_data" is not aligned with 4 byte, in some cpu convert it to
// pointer "ble_bind_data *" work correctly, but some cpu will get wrong value, or cause
// other "Unexpected Error". Here copy it to a local variable make sure aligned with 4 byte.
ble_conn_data conn_data_aligned;
memcpy(&conn_data_aligned, conn_data, sizeof(ble_conn_data));
// valid sign
timestamp = NTOHL(conn_data_aligned.timestamp);
snprintf(sign_info + sign_info_len, sizeof(sign_info) - sign_info_len, "%d", timestamp);
sign_info_len += strlen(sign_info + sign_info_len);
ble_qiot_log_hex(BLE_QIOT_LOG_LEVEL_INFO, "valid sign in", sign_info, sign_info_len);
utils_hmac_sha1(sign_info, sign_info_len, out_sign, sg_core_data.local_psk, sizeof(sg_core_data.local_psk));
ble_qiot_log_hex(BLE_QIOT_LOG_LEVEL_INFO, "valid sign out", out_sign, SHA1_DIGEST_SIZE);
if (0 != memcmp(&conn_data_aligned.sign_info, out_sign, SHA1_DIGEST_SIZE)) {
ble_qiot_log_e("invalid connect sign");
return BLE_QIOT_RS_VALID_SIGN_ERR;
}
// calc sign
memset(sign_info, 0, sizeof(sign_info));
sign_info_len = 0;
// expiration time + product id + device name
timestamp = BLE_GET_EXPIRATION_TIME(NTOHL(conn_data_aligned.timestamp));
snprintf(sign_info + sign_info_len, sizeof(sign_info) - sign_info_len, "%d", timestamp);
sign_info_len += strlen(sign_info + sign_info_len);
memcpy(sign_info + sign_info_len, sg_device_info.product_id, sizeof(sg_device_info.product_id));
sign_info_len += sizeof(sg_device_info.product_id);
memcpy(sign_info + sign_info_len, sg_device_info.device_name, strlen(sg_device_info.device_name));
sign_info_len += strlen(sg_device_info.device_name);
ble_qiot_log_hex(BLE_QIOT_LOG_LEVEL_INFO, "conn sign in", sign_info, sign_info_len);
utils_hmac_sha1(sign_info, sign_info_len, out_sign, sg_core_data.local_psk, sizeof(sg_core_data.local_psk));
ble_qiot_log_hex(BLE_QIOT_LOG_LEVEL_INFO, "conn sign out", out_sign, sizeof(out_sign));
// return authcode
memset(out_buf, 0, buf_len);
memcpy(out_buf, out_sign, SHA1_DIGEST_SIZE);
ret_len += SHA1_DIGEST_SIZE;
memcpy(out_buf + ret_len, sg_device_info.device_name, strlen(sg_device_info.device_name));
ret_len += strlen(sg_device_info.device_name);
ble_qiot_log_hex(BLE_QIOT_LOG_LEVEL_INFO, "conn auth code", out_buf, ret_len);
return ret_len;
}
int ble_unbind_get_authcode(const char *unbind_data, uint16_t data_len, char *out_buf, uint16_t buf_len)
{
POINTER_SANITY_CHECK(unbind_data, BLE_QIOT_RS_ERR_PARA);
BUFF_LEN_SANITY_CHECK(data_len, (int32_t)sizeof(ble_unbind_data), BLE_QIOT_RS_ERR_PARA);
POINTER_SANITY_CHECK(out_buf, BLE_QIOT_RS_ERR_PARA);
BUFF_LEN_SANITY_CHECK(buf_len, SHA1_DIGEST_SIZE, BLE_QIOT_RS_ERR_PARA);
char sign_info[32] = {0};
char out_sign[SHA1_DIGEST_SIZE] = {0};
int sign_info_len = 0;
int ret_len = 0;
// valid sign
memcpy(sign_info, BLE_UNBIND_REQUEST_STR, BLE_UNBIND_REQUEST_STR_LEN);
sign_info_len += BLE_UNBIND_REQUEST_STR_LEN;
utils_hmac_sha1(sign_info, sign_info_len, out_sign, sg_core_data.local_psk, sizeof(sg_core_data.local_psk));
ble_qiot_log_hex(BLE_QIOT_LOG_LEVEL_INFO, "valid sign out", out_sign, SHA1_DIGEST_SIZE);
if (0 != memcmp(((ble_unbind_data *)unbind_data)->sign_info, out_sign, SHA1_DIGEST_SIZE)) {
ble_qiot_log_e("invalid unbind sign");
return BLE_QIOT_RS_VALID_SIGN_ERR;
}
// calc sign
memset(sign_info, 0, sizeof(sign_info));
sign_info_len = 0;
memcpy(sign_info, BLE_UNBIND_RESPONSE, strlen(BLE_UNBIND_RESPONSE));
sign_info_len += BLE_UNBIND_RESPONSE_STR_LEN;
utils_hmac_sha1(sign_info, sign_info_len, out_sign, sg_core_data.local_psk, sizeof(sg_core_data.local_psk));
ble_qiot_log_hex(BLE_QIOT_LOG_LEVEL_INFO, "unbind auth code", out_sign, SHA1_DIGEST_SIZE);
memset(out_buf, 0, buf_len);
memcpy(out_buf, out_sign, sizeof(out_sign));
ret_len += sizeof(out_sign);
return ret_len;
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,198 @@
/*
* 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_llsync_event.h"
#include <stdbool.h>
#include <string.h>
#include "ble_qiot_import.h"
#include "ble_qiot_common.h"
#include "ble_qiot_param_check.h"
#include "ble_qiot_service.h"
#include "ble_qiot_template.h"
#include "ble_qiot_llsync_device.h"
ble_qiot_ret_status_t ble_event_get_status(void)
{
#ifdef BLE_QIOT_INCLUDE_PROPERTY
return ble_event_notify(BLE_QIOT_EVENT_UP_GET_STATUS, NULL, 0, NULL, 0);
#else
ble_qiot_log_e("llsync property not support");
return BLE_QIOT_RS_OK;
#endif
}
ble_qiot_ret_status_t ble_event_report_property(void)
{
#ifdef BLE_QIOT_INCLUDE_PROPERTY
return ble_user_property_get_report_data();
#else
ble_qiot_log_e("llsync property not support");
return BLE_QIOT_RS_OK;
#endif
}
ble_qiot_ret_status_t ble_event_report_device_info(void)
{
char device_info[3] = {0};
uint16_t mtu_size = 0;
mtu_size = ble_get_user_data_mtu_size();
mtu_size = HTONS(mtu_size);
device_info[0] = BLE_QIOT_LLSYNC_PROTOCOL_VERSION;
memcpy(&device_info[1], &mtu_size, sizeof(mtu_size));
return ble_event_notify(BLE_QIOT_EVENT_UP_REPORT_MTU, NULL, 0, (const char *)device_info, sizeof(device_info));
}
ble_qiot_ret_status_t ble_event_notify(uint8_t type, uint8_t *header, uint8_t header_len, const char *buf,
uint16_t buf_len)
{
char * p = NULL;
uint16_t left_len = 0;
uint16_t send_len = 0;
uint16_t mtu_size = 0;
uint8_t slice_state = BLE_QIOT_EVENT_NO_SLICE;
uint8_t send_buf[BLE_QIOT_EVENT_BUF_SIZE] = {0};
uint16_t send_buf_index = 0;
uint16_t tmp_len = 0;
if (!llsync_is_connected() && type != BLE_QIOT_EVENT_UP_BIND_SIGN_RET && type != BLE_QIOT_EVENT_UP_CONN_SIGN_RET &&
type != BLE_QIOT_EVENT_UP_UNBIND_SIGN_RET) {
ble_qiot_log_e("upload msg negate, device not connected");
return BLE_QIOT_RS_ERR;
}
// reserve event header length, 3 bytes fixed length + n bytes header
mtu_size = ble_get_user_data_mtu_size();
mtu_size = mtu_size > sizeof(send_buf) ? sizeof(send_buf) : mtu_size;
mtu_size -= (BLE_QIOT_EVENT_FIXED_HEADER_LEN + header_len);
ble_qiot_log_d("mtu size %d", mtu_size);
p = (char *)buf;
left_len = buf_len;
do {
memset(send_buf, 0, sizeof(send_buf));
send_buf_index = 0;
send_len = left_len > mtu_size ? mtu_size : left_len;
send_buf[send_buf_index++] = type;
if (NULL != buf) {
tmp_len = HTONS(send_len + header_len);
memcpy(send_buf + send_buf_index, &tmp_len, sizeof(uint16_t));
send_buf_index += sizeof(uint16_t);
if (NULL != header) {
memcpy(send_buf + send_buf_index, header, header_len);
send_buf_index += header_len;
}
memcpy(send_buf + send_buf_index, p, send_len);
send_buf_index += send_len;
p += send_len;
left_len -= send_len;
// add event id
send_len += (BLE_QIOT_EVENT_FIXED_HEADER_LEN + header_len);
if (0 == left_len) {
if (BLE_QIOT_EVENT_NO_SLICE == slice_state) {
slice_state = BLE_QIOT_EVENT_NO_SLICE;
} else {
slice_state = BLE_QIOT_EVENT_SLICE_FOOT;
}
} else {
if (BLE_QIOT_EVENT_NO_SLICE == slice_state) {
slice_state = BLE_QIOT_EVENT_SLICE_HEAD;
} else {
slice_state = BLE_QIOT_EVENT_SLICE_BODY;
}
}
// the high 2 bits means slice state, and the left 14 bits is data length
send_buf[1] |= slice_state << 6;
} else {
send_len = send_buf_index;
}
ble_qiot_log_hex(BLE_QIOT_LOG_LEVEL_INFO, "post data", (char *)send_buf, send_len);
if (0 != ble_send_notify(send_buf, send_len)) {
ble_qiot_log_e("event post failed, type %d", type);
return BLE_QIOT_RS_ERR;
}
} while (left_len != 0);
return BLE_QIOT_RS_OK;
}
ble_qiot_ret_status_t ble_event_post(uint8_t event_id)
{
#ifdef BLE_QIOT_INCLUDE_EVENT
uint8_t param_id = 0;
uint8_t param_id_size = 0;
uint8_t param_type = 0;
int param_len = 0;
uint8_t data_buf[BLE_QIOT_EVENT_MAX_SIZE] = {0};
uint16_t data_len = 0;
uint16_t string_len = 0;
uint8_t header_buf[1] = {0};
ble_qiot_log_d("post event %d", event_id);
param_id_size = ble_event_get_id_array_size(event_id);
// get all the data
for (param_id = 0; param_id < param_id_size; param_id++) {
param_type = ble_event_get_param_id_type(event_id, param_id);
if (param_type == BLE_QIOT_DATA_TYPE_BUTT) {
ble_qiot_log_e("invalid type, event id %d, param id %d", event_id, param_id);
return BLE_QIOT_RS_ERR;
}
data_buf[data_len++] = BLE_QIOT_PACKAGE_TLV_HEAD(param_type, param_id);
if (BLE_QIOT_DATA_TYPE_STRING == param_type) {
// reserved 2 bytes for string length, other type have fixed length
param_len = ble_event_get_data_by_id(event_id, param_id, (char *)data_buf + data_len + 2,
sizeof(data_buf) - data_len - 2);
} else {
param_len =
ble_event_get_data_by_id(event_id, param_id, (char *)data_buf + data_len, sizeof(data_buf) - data_len);
}
if (param_len < 0) {
ble_qiot_log_e("too long data, event id %d, data length %d", event_id, data_len);
return BLE_QIOT_RS_ERR;
} else if (param_len == 0) {
// no data to post
data_len--;
data_buf[data_len] = '0';
ble_qiot_log_d("param id %d no data to post", param_id);
} else {
if (BLE_QIOT_DATA_TYPE_STRING == param_type) {
string_len = HTONS(param_len);
memcpy(data_buf + data_len, &string_len, sizeof(uint16_t));
data_len += sizeof(uint16_t);
}
data_len += param_len;
}
}
header_buf[0] = event_id;
return ble_event_notify(BLE_QIOT_EVENT_UP_EVENT_POST, header_buf, sizeof(header_buf), (const char *)data_buf,
data_len);
#else
ble_qiot_log_e("llsync event not support");
return BLE_QIOT_RS_ERR;
#endif
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,508 @@
/*
* 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_service.h"
#include <stdio.h>
#include "ble_qiot_export.h"
#include "ble_qiot_import.h"
#include "ble_qiot_llsync_data.h"
#include "ble_qiot_llsync_device.h"
#include "ble_qiot_llsync_event.h"
#include "ble_qiot_log.h"
#include "ble_qiot_param_check.h"
#include "ble_qiot_service.h"
#include "ble_qiot_template.h"
// llsync support data fragment, so we need to package all the data before parsing if the data is slice
static ble_event_slice_t sg_ble_slice_data;
#if (1 == BLE_QIOT_BUTTON_BROADCAST)
static ble_timer_t sg_bind_timer = NULL;
#endif
static qiot_service_init_s service_info = {
.service_uuid16 = IOT_BLE_UUID_SERVICE,
.service_uuid128 = IOT_BLE_UUID_BASE,
.device_info =
{
.uuid16 = IOT_BLE_UUID_DEVICE_INFO,
.gatt_char_props = GATT_CHAR_WRITE,
.on_write = ble_device_info_write_cb,
},
.data =
{
.uuid16 = IOT_BLE_UUID_DATA,
.gatt_char_props = GATT_CHAR_WRITE,
.on_write = ble_lldata_write_cb,
},
.event =
{
.uuid16 = IOT_BLE_UUID_EVENT,
.gatt_char_props = GATT_CHAR_NOTIFY,
.on_write = NULL,
},
};
const qiot_service_init_s *ble_get_qiot_services(void)
{
return &service_info;
}
#if (1 == BLE_QIOT_BUTTON_BROADCAST)
static void ble_bind_timer_callback(void *param)
{
ble_qiot_log_i("timer timeout");
if (E_LLSYNC_BIND_WAIT == llsync_bind_state_get()) {
ble_advertising_stop();
llsync_bind_state_set(E_LLSYNC_BIND_IDLE);
ble_qiot_log_i("stop advertising");
}
}
#endif
ble_qiot_ret_status_t ble_qiot_advertising_start(void)
{
adv_info_s my_adv_info;
uint16_t uuids[1];
uint8_t adv_data[32] = {0};
uint8_t adv_data_len = 0;
uuids[0] = IOT_BLE_UUID_SERVICE;
my_adv_info.uuid_info.uuid_num = 1;
my_adv_info.uuid_info.uuids = uuids;
if (E_LLSYNC_BIND_IDLE == llsync_bind_state_get()) {
#if (1 == BLE_QIOT_BUTTON_BROADCAST)
if (NULL == sg_bind_timer) {
sg_bind_timer = ble_timer_create(BLE_TIMER_ONE_SHOT_TYPE, ble_bind_timer_callback);
if (NULL == sg_bind_timer) {
ble_qiot_log_i("create bind timer failed");
return BLE_QIOT_RS_ERR;
}
}
#endif
ble_advertising_stop();
llsync_bind_state_set(E_LLSYNC_BIND_WAIT);
adv_data_len = ble_get_my_broadcast_data((char *)adv_data, sizeof(adv_data));
my_adv_info.manufacturer_info.company_identifier = TENCENT_COMPANY_IDENTIFIER;
my_adv_info.manufacturer_info.adv_data = adv_data;
my_adv_info.manufacturer_info.adv_data_len = adv_data_len;
ble_advertising_start(&my_adv_info);
ble_qiot_log_i("start wait advertising");
#if (1 == BLE_QIOT_BUTTON_BROADCAST)
ble_timer_start(sg_bind_timer, BLE_QIOT_BIND_TIMEOUT);
#endif
} else if (E_LLSYNC_BIND_WAIT == llsync_bind_state_get()) {
ble_advertising_stop();
llsync_bind_state_set(E_LLSYNC_BIND_WAIT);
adv_data_len = ble_get_my_broadcast_data((char *)adv_data, sizeof(adv_data));
my_adv_info.manufacturer_info.company_identifier = TENCENT_COMPANY_IDENTIFIER;
my_adv_info.manufacturer_info.adv_data = adv_data;
my_adv_info.manufacturer_info.adv_data_len = adv_data_len;
ble_advertising_start(&my_adv_info);
ble_qiot_log_i("restart wait advertising");
#if (1 == BLE_QIOT_BUTTON_BROADCAST)
ble_timer_stop(sg_bind_timer);
ble_timer_start(sg_bind_timer, BLE_QIOT_BIND_TIMEOUT);
#endif
} else if (E_LLSYNC_BIND_SUCC == llsync_bind_state_get()) {
ble_advertising_stop();
adv_data_len = ble_get_my_broadcast_data((char *)adv_data, sizeof(adv_data));
my_adv_info.manufacturer_info.company_identifier = TENCENT_COMPANY_IDENTIFIER;
my_adv_info.manufacturer_info.adv_data = adv_data;
my_adv_info.manufacturer_info.adv_data_len = adv_data_len;
ble_advertising_start(&my_adv_info);
ble_qiot_log_i("start bind advertising");
} else {
// do nothing
}
return BLE_QIOT_RS_OK;
}
ble_qiot_ret_status_t ble_qiot_advertising_stop(void)
{
return 0 == ble_advertising_stop() ? BLE_QIOT_RS_OK : BLE_QIOT_RS_ERR;
}
ble_qiot_ret_status_t ble_qiot_explorer_init(void)
{
ble_qiot_ret_status_t ret_code = BLE_QIOT_RS_OK;
const qiot_service_init_s *service_info = NULL;
ble_qiot_set_log_level(BLE_QIOT_LOG_LEVEL_INFO);
service_info = ble_get_qiot_services();
ble_services_add(service_info);
ret_code = ble_init_flash_data();
if (ret_code != BLE_QIOT_RS_OK) {
ble_qiot_log_e("flash init failed, ret code %d", ret_code);
}
return ret_code;
}
void ble_device_info_write_cb(const uint8_t *buf, uint16_t len)
{
ble_device_info_msg_handle((const char *)buf, len);
}
void ble_lldata_write_cb(const uint8_t *buf, uint16_t len)
{
ble_lldata_msg_handle((const char *)buf, len);
}
// when gap get ble connect event, use this function
void ble_gap_connect_cb(void)
{
ble_connection_state_set(E_BLE_CONNECTED);
}
// when gap get ble disconnect event, use this function
void ble_gap_disconnect_cb(void)
{
llsync_connection_state_set(E_LLSYNC_DISCONNECTED);
ble_connection_state_set(E_BLE_DISCONNECTED);
}
static uint8_t ble_msg_type_header_len(uint8_t type)
{
if (type == BLE_QIOT_GET_STATUS_REPLY_DATA_TYPE) {
return BLE_QIOT_GET_STATUS_REPLY_HEADER_LEN;
} else {
return BLE_QIOT_DATA_FIXED_HEADER_LEN;
}
}
int ble_device_info_msg_handle(const char *in_buf, int in_len)
{
POINTER_SANITY_CHECK(in_buf, BLE_QIOT_RS_ERR_PARA);
uint8_t ch;
char out_buf[80] = {0};
uint8_t slice_flag = 0;
uint8_t header_len = 0;
uint8_t slice_type = 0;
uint16_t tmp_len = 0;
char * p_data = NULL;
int p_data_len = 0;
int ret_len = 0;
int ret = BLE_QIOT_RS_OK;
p_data = (char *)in_buf;
p_data_len = in_len;
// E_DEV_MSG_SYNC_TIME, E_DEV_MSG_CONN_VALID, E_DEV_MSG_BIND_SUCC, E_DEV_MSG_UNBIND this 4 type
// of message has more than one bytes data, it may cut to several slices, here need to merge them
// together, other type message only has 1 byte data, not need merge.
if(in_len > 3) {
slice_type = in_buf[0];
slice_flag = in_buf[1];
if (BLE_QIOT_IS_SLICE_PACKAGE(slice_flag)) {
if (BLE_QIOT_IS_SLICE_HEADER(slice_flag)) {
if (sg_ble_slice_data.have_data) {
ble_qiot_log_e("new data coming when package msg, clear the buffer");
memset(&sg_ble_slice_data, 0, sizeof(sg_ble_slice_data));
}
sg_ble_slice_data.have_data = true;
sg_ble_slice_data.type = slice_type;
header_len = ble_msg_type_header_len(slice_type);
// reserved data length space
sg_ble_slice_data.buf_len += header_len;
sg_ble_slice_data.buf[0] = in_buf[0];
if (BLE_QIOT_GET_STATUS_REPLY_DATA_TYPE == slice_type) {
sg_ble_slice_data.buf[1] = in_buf[1];
}
memcpy(sg_ble_slice_data.buf + sg_ble_slice_data.buf_len, in_buf + header_len, in_len - header_len);
sg_ble_slice_data.buf_len += (in_len - header_len);
return BLE_QIOT_RS_OK;
} else if (BLE_QIOT_IS_SLICE_BODY(slice_flag)) {
if (!sg_ble_slice_data.have_data) {
ble_qiot_log_e("slice no header package");
return BLE_QIOT_RS_ERR;
}
if (slice_type != sg_ble_slice_data.type) {
ble_qiot_log_e("invalid msg type %d, except msg type %d", slice_type, sg_ble_slice_data.type);
return BLE_QIOT_RS_ERR;
}
if (sg_ble_slice_data.buf_len + (in_len - header_len) > sizeof(sg_ble_slice_data.buf)) {
ble_qiot_log_e("slice data is too long, max length %d", sizeof(sg_ble_slice_data.buf));
return BLE_QIOT_RS_ERR;
}
header_len = ble_msg_type_header_len(slice_type);
memcpy(sg_ble_slice_data.buf + sg_ble_slice_data.buf_len, in_buf + header_len, in_len - header_len);
sg_ble_slice_data.buf_len += (in_len - header_len);
return BLE_QIOT_RS_OK;
} else {
if (!sg_ble_slice_data.have_data) {
ble_qiot_log_e("slice no header package");
return BLE_QIOT_RS_ERR;
}
if (slice_type != sg_ble_slice_data.type) {
ble_qiot_log_e("invalid msg type %d, except msg type %d", slice_type, sg_ble_slice_data.type);
return BLE_QIOT_RS_ERR;
}
if (sg_ble_slice_data.buf_len + (in_len - header_len) > sizeof(sg_ble_slice_data.buf)) {
ble_qiot_log_e("slice data is too long, max length %d", sizeof(sg_ble_slice_data.buf));
return BLE_QIOT_RS_ERR;
}
header_len = ble_msg_type_header_len(slice_type);
memcpy(sg_ble_slice_data.buf + sg_ble_slice_data.buf_len, in_buf + header_len, in_len - header_len);
sg_ble_slice_data.buf_len += (in_len - header_len);
// write data length
tmp_len = HTONS(sg_ble_slice_data.buf_len - header_len);
if (BLE_QIOT_GET_STATUS_REPLY_DATA_TYPE == slice_type) {
memcpy(&sg_ble_slice_data.buf[2], &tmp_len, sizeof(tmp_len));
} else {
memcpy(&sg_ble_slice_data.buf[1], &tmp_len, sizeof(tmp_len));
}
p_data = sg_ble_slice_data.buf;
p_data_len = sg_ble_slice_data.buf_len;
// ble_qiot_log_hex(BLE_QIOT_LOG_LEVEL_INFO, "tlv", p_data, p_data_len);
}
} else {
ble_qiot_log_d("data not slice");
}
}
// ch = in_buf[0];
ch = p_data[0];
switch (ch) {
case E_DEV_MSG_SYNC_TIME:
ret_len = ble_bind_get_authcode(p_data + 3, p_data_len - 3, out_buf, sizeof(out_buf));
if (ret_len <= 0) {
ble_qiot_log_e("get bind authcode failed");
ret = BLE_QIOT_RS_ERR;
break;
}
ret = ble_event_notify((uint8_t)BLE_QIOT_EVENT_UP_BIND_SIGN_RET, NULL, 0, out_buf, ret_len);
break;
case E_DEV_MSG_CONN_VALID:
ret_len = ble_conn_get_authcode(p_data + 3, p_data_len - 3, out_buf, sizeof(out_buf));
if (ret_len <= 0) {
ble_qiot_log_e("get connect authcode failed");
ret = BLE_QIOT_RS_ERR;
break;
}
ret = ble_event_notify((uint8_t)BLE_QIOT_EVENT_UP_CONN_SIGN_RET, NULL, 0, out_buf, ret_len);
break;
case E_DEV_MSG_BIND_SUCC:
if (BLE_QIOT_RS_OK != ble_bind_write_result(p_data + 3, p_data_len - 3)) {
ble_qiot_log_e("write bind result failed");
ret = BLE_QIOT_RS_ERR;
break;
}
break;
case E_DEV_MSG_BIND_FAIL:
ble_qiot_log_i("get msg bind fail");
break;
case E_DEV_MSG_UNBIND:
ret_len = ble_unbind_get_authcode(p_data + 3, p_data_len - 3, out_buf, sizeof(out_buf));
if (ret_len <= 0) {
ble_qiot_log_e("get unbind authcode failed");
ret = BLE_QIOT_RS_ERR;
break;
}
ret = ble_event_notify((uint8_t)BLE_QIOT_EVENT_UP_UNBIND_SIGN_RET, NULL, 0, out_buf, ret_len);
break;
case E_DEV_MSG_CONN_SUCC:
ble_qiot_log_i("get msg connect success");
llsync_connection_state_set(E_LLSYNC_CONNECTED);
ret = ble_event_report_device_info();
break;
case E_DEV_MSG_CONN_FAIL:
ble_qiot_log_i("get msg connect fail");
break;
case E_DEV_MSG_UNBIND_SUCC:
ble_qiot_log_i("get msg unbind success");
if (BLE_QIOT_RS_OK != ble_unbind_write_result()) {
ble_qiot_log_e("write unbind result failed");
ret = BLE_QIOT_RS_ERR;
break;
}
break;
case E_DEV_MSG_UNBIND_FAIL:
ble_qiot_log_i("get msg unbind fail");
break;
default:
break;
}
memset(&sg_ble_slice_data, 0, sizeof(sg_ble_slice_data));
return ret;
}
// lldata message from remote
int ble_lldata_msg_handle(const char *in_buf, int in_len)
{
POINTER_SANITY_CHECK(in_buf, BLE_QIOT_RS_ERR_PARA);
uint8_t data_type = 0;
uint8_t data_effect = 0;
uint8_t id = 0;
uint8_t slice_flag = 0;
uint8_t header_len = 0;
uint8_t slice_type = 0;
uint16_t tmp_len = 0;
char * p_data = NULL;
int p_data_len = 0;
int ret = 0;
if (!llsync_is_connected()) {
ble_qiot_log_e("operation negate, device not connected");
return BLE_QIOT_RS_ERR;
}
p_data = (char *)in_buf;
p_data_len = in_len;
data_type = BLE_QIOT_PARSE_MSG_HEAD_TYPE(in_buf[0]);
if (data_type >= BLE_QIOT_DATA_TYPE_BUTT) {
ble_qiot_log_e("invalid data type %d", data_type);
return BLE_QIOT_RS_ERR;
}
data_effect = BLE_QIOT_PARSE_MSG_HEAD_EFFECT(in_buf[0]);
if (data_effect >= BLE_QIOT_EFFECT_BUTT) {
ble_qiot_log_e("invalid data effect %d", data_effect);
return BLE_QIOT_RS_ERR;
}
id = BLE_QIOT_PARSE_MSG_HEAD_ID(in_buf[0]);
ble_qiot_log_d("data type %d, effect %d, id %d", data_type, data_effect, id);
// if data is action_reply, control or get_status_reply, the data maybe need package
if ((data_type == BLE_QIOT_MSG_TYPE_ACTION) || (in_buf[0] == BLE_QIOT_CONTROL_DATA_TYPE) ||
(in_buf[0] == BLE_QIOT_GET_STATUS_REPLY_DATA_TYPE)) {
if (in_buf[0] == BLE_QIOT_GET_STATUS_REPLY_DATA_TYPE) {
slice_flag = in_buf[2];
slice_type = in_buf[0];
} else {
slice_flag = in_buf[1];
slice_type = data_type;
}
if (BLE_QIOT_IS_SLICE_PACKAGE(slice_flag)) {
if (BLE_QIOT_IS_SLICE_HEADER(slice_flag)) {
if (sg_ble_slice_data.have_data) {
ble_qiot_log_e("new data coming when package msg, clear the buffer");
memset(&sg_ble_slice_data, 0, sizeof(sg_ble_slice_data));
}
sg_ble_slice_data.have_data = true;
sg_ble_slice_data.type = slice_type;
header_len = ble_msg_type_header_len(slice_type);
// reserved data length space
sg_ble_slice_data.buf_len += header_len;
sg_ble_slice_data.buf[0] = in_buf[0];
if (BLE_QIOT_GET_STATUS_REPLY_DATA_TYPE == slice_type) {
sg_ble_slice_data.buf[1] = in_buf[1];
}
memcpy(sg_ble_slice_data.buf + sg_ble_slice_data.buf_len, in_buf + header_len, in_len - header_len);
sg_ble_slice_data.buf_len += (in_len - header_len);
return BLE_QIOT_RS_OK;
} else if (BLE_QIOT_IS_SLICE_BODY(slice_flag)) {
if (!sg_ble_slice_data.have_data) {
ble_qiot_log_e("slice no header package");
return BLE_QIOT_RS_ERR;
}
if (slice_type != sg_ble_slice_data.type) {
ble_qiot_log_e("invalid msg type %d, except msg type %d", slice_type, sg_ble_slice_data.type);
return BLE_QIOT_RS_ERR;
}
if (sg_ble_slice_data.buf_len + (in_len - header_len) > sizeof(sg_ble_slice_data.buf)) {
ble_qiot_log_e("slice data is too long, max length %d", sizeof(sg_ble_slice_data.buf));
return BLE_QIOT_RS_ERR;
}
header_len = ble_msg_type_header_len(slice_type);
memcpy(sg_ble_slice_data.buf + sg_ble_slice_data.buf_len, in_buf + header_len, in_len - header_len);
sg_ble_slice_data.buf_len += (in_len - header_len);
return BLE_QIOT_RS_OK;
} else {
if (!sg_ble_slice_data.have_data) {
ble_qiot_log_e("slice no header package");
return BLE_QIOT_RS_ERR;
}
if (slice_type != sg_ble_slice_data.type) {
ble_qiot_log_e("invalid msg type %d, except msg type %d", slice_type, sg_ble_slice_data.type);
return BLE_QIOT_RS_ERR;
}
if (sg_ble_slice_data.buf_len + (in_len - header_len) > sizeof(sg_ble_slice_data.buf)) {
ble_qiot_log_e("slice data is too long, max length %d", sizeof(sg_ble_slice_data.buf));
return BLE_QIOT_RS_ERR;
}
header_len = ble_msg_type_header_len(slice_type);
memcpy(sg_ble_slice_data.buf + sg_ble_slice_data.buf_len, in_buf + header_len, in_len - header_len);
sg_ble_slice_data.buf_len += (in_len - header_len);
// write data length
tmp_len = HTONS(sg_ble_slice_data.buf_len - header_len);
if (BLE_QIOT_GET_STATUS_REPLY_DATA_TYPE == slice_type) {
memcpy(&sg_ble_slice_data.buf[2], &tmp_len, sizeof(tmp_len));
} else {
memcpy(&sg_ble_slice_data.buf[1], &tmp_len, sizeof(tmp_len));
}
p_data = sg_ble_slice_data.buf;
p_data_len = sg_ble_slice_data.buf_len;
// ble_qiot_log_hex(BLE_QIOT_LOG_LEVEL_INFO, "tlv", p_data, p_data_len);
}
} else {
ble_qiot_log_d("data not slice");
}
}
switch (data_type) {
case BLE_QIOT_MSG_TYPE_PROPERTY:
if (BLE_QIOT_EFFECT_REQUEST == data_effect) {
// default E_BLE_DATA_DOWN_TYPE_CONTROL
ret = ble_lldata_property_request_handle(p_data + 3, p_data_len - 3);
} else if (BLE_QIOT_EFFECT_REPLY == data_effect) {
// id means BLE_QIOT_DATA_DOWN_GET_STATUS_REPLY or BLE_QIOT_DATA_DOWN_REPORT_REPLY
ret = ble_lldata_property_reply_handle(id, p_data + 1, p_data_len - 1);
} else {
ret = BLE_QIOT_RS_ERR;
}
break;
case BLE_QIOT_MSG_TYPE_EVENT:
if (BLE_QIOT_EFFECT_REPLY == data_effect) {
ret = ble_lldata_event_handle(id, p_data + 1, p_data_len - 1);
} else {
ble_qiot_log_e("invalid event data effect");
ret = BLE_QIOT_RS_ERR;
}
break;
case BLE_QIOT_MSG_TYPE_ACTION:
if (BLE_QIOT_EFFECT_REQUEST == data_effect) {
ret = ble_lldata_action_handle(id, p_data + 3, p_data_len - 3);
} else {
ble_qiot_log_e("invalid action data effect");
ret = BLE_QIOT_RS_ERR;
}
break;
default:
break;
}
memset(&sg_ble_slice_data, 0, sizeof(sg_ble_slice_data));
return ret;
}
#ifdef __cplusplus
}
#endif

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,35 @@
/*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
* Licensed under the MIT License (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://opensource.org/licenses/MIT
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#ifndef QCLOUD_BLE_IOT_SERVICE_H_
#define QCLOUD_BLE_IOT_SERVICE_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include "ble_qiot_export.h"
#include "ble_qiot_llsync_data.h"
#include "ble_qiot_template.h"
// handle llsync device info
// return 0 is success, other is error
int ble_device_info_msg_handle(const char *in_buf, int in_len);
// lldata message from remote
// return 0 is success, other is error
int ble_lldata_msg_handle(const char *in_buf, int in_len);
#ifdef __cplusplus
}
#endif
#endif // QCLOUD_BLE_IOT_SERVICE_H_

Some files were not shown because too many files have changed in this diff Show More