627 lines
16 KiB
C
627 lines
16 KiB
C
/********************************** (C) COPYRIGHT *******************************
|
|
* File Name : app.c
|
|
* Author : WCH
|
|
* Version : V1.1
|
|
* Date : 2021/11/10
|
|
* Description :
|
|
*********************************************************************************
|
|
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
|
|
* Attention: This software (modified or not) and binary are used for
|
|
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
|
|
*******************************************************************************/
|
|
|
|
/******************************************************************************/
|
|
#include "CONFIG.h"
|
|
#include "MESH_LIB.h"
|
|
#include "app_vendor_model.h"
|
|
#include "app_generic_onoff_model.h"
|
|
#include "app.h"
|
|
#include "HAL.h"
|
|
|
|
/*********************************************************************
|
|
* GLOBAL TYPEDEFS
|
|
*/
|
|
#define ADV_TIMEOUT K_MINUTES(10)
|
|
|
|
#define SELENCE_ADV_ON 0x01
|
|
#define SELENCE_ADV_OF 0x00
|
|
|
|
/*********************************************************************
|
|
* GLOBAL TYPEDEFS
|
|
*/
|
|
|
|
static uint8_t MESH_MEM[1024 * 2] = {0};
|
|
|
|
extern const ble_mesh_cfg_t app_mesh_cfg;
|
|
extern const struct device app_dev;
|
|
|
|
static uint8_t App_TaskID = 0; // Task ID for internal task/event processing
|
|
|
|
static uint16_t App_ProcessEvent(uint8_t task_id, uint16_t events);
|
|
|
|
#if(!CONFIG_BLE_MESH_PB_GATT)
|
|
NET_BUF_SIMPLE_DEFINE_STATIC(rx_buf, 65);
|
|
#endif /* !PB_GATT */
|
|
|
|
/*********************************************************************
|
|
* LOCAL FUNCION
|
|
*/
|
|
|
|
static void link_open(bt_mesh_prov_bearer_t bearer);
|
|
static void link_close(bt_mesh_prov_bearer_t bearer, uint8_t reason);
|
|
static void prov_complete(uint16_t net_idx, uint16_t addr, uint8_t flags, uint32_t iv_index);
|
|
static void prov_reset(void);
|
|
|
|
static struct bt_mesh_cfg_srv cfg_srv = {
|
|
.relay = BLE_MESH_RELAY_ENABLED,
|
|
.beacon = BLE_MESH_BEACON_ENABLED,
|
|
#if(CONFIG_BLE_MESH_FRIEND)
|
|
.frnd = BLE_MESH_FRIEND_ENABLED,
|
|
#endif
|
|
#if(CONFIG_BLE_MESH_PROXY)
|
|
.gatt_proxy = BLE_MESH_GATT_PROXY_ENABLED,
|
|
#endif
|
|
.default_ttl = 3,
|
|
|
|
/* 8 transmissions with 10ms interval */
|
|
.net_transmit = BLE_MESH_TRANSMIT(7, 10),
|
|
.relay_retransmit = BLE_MESH_TRANSMIT(7, 10),
|
|
};
|
|
|
|
static struct bt_mesh_health_srv health_srv;
|
|
|
|
BLE_MESH_HEALTH_PUB_DEFINE(health_pub, 8);
|
|
|
|
uint16_t cfg_srv_keys[CONFIG_MESH_MOD_KEY_COUNT_DEF] = {BLE_MESH_KEY_UNUSED};
|
|
uint16_t cfg_srv_groups[CONFIG_MESH_MOD_GROUP_COUNT_DEF] = {BLE_MESH_ADDR_UNASSIGNED};
|
|
|
|
uint16_t health_srv_keys[CONFIG_MESH_MOD_KEY_COUNT_DEF] = {BLE_MESH_KEY_UNUSED};
|
|
uint16_t health_srv_groups[CONFIG_MESH_MOD_GROUP_COUNT_DEF] = {BLE_MESH_ADDR_UNASSIGNED};
|
|
|
|
uint16_t gen_onoff_srv_keys[CONFIG_MESH_MOD_KEY_COUNT_DEF] = {BLE_MESH_KEY_UNUSED};
|
|
uint16_t gen_onoff_srv_groups[CONFIG_MESH_MOD_GROUP_COUNT_DEF] = {BLE_MESH_ADDR_UNASSIGNED};
|
|
|
|
static struct bt_mesh_model root_models[] = {
|
|
BLE_MESH_MODEL_CFG_SRV(cfg_srv_keys, cfg_srv_groups, &cfg_srv),
|
|
BLE_MESH_MODEL_HEALTH_SRV(health_srv_keys, health_srv_groups, &health_srv, &health_pub),
|
|
BLE_MESH_MODEL(BLE_MESH_MODEL_ID_GEN_ONOFF_SRV, gen_onoff_op, NULL, gen_onoff_srv_keys, gen_onoff_srv_groups, NULL),
|
|
};
|
|
|
|
static struct bt_mesh_elem elements[] = {
|
|
{
|
|
/* Location Descriptor (GATT Bluetooth Namespace Descriptors) */
|
|
.loc = (0),
|
|
.model_count = ARRAY_SIZE(root_models),
|
|
.models = (root_models),
|
|
.vnd_model_count = ARRAY_SIZE(vnd_models),
|
|
.vnd_models = (vnd_models),
|
|
}
|
|
};
|
|
|
|
// elements 构成 Node Composition
|
|
const struct bt_mesh_comp app_comp = {
|
|
.cid = 0x07D7, // WCH 公司id
|
|
.elem = elements,
|
|
.elem_count = ARRAY_SIZE(elements),
|
|
};
|
|
|
|
// 配网参数和回调
|
|
static const struct bt_mesh_prov app_prov = {
|
|
.uuid = tm_uuid,
|
|
.static_val_len = ARRAY_SIZE(static_key),
|
|
.static_val = static_key,
|
|
.link_open = link_open,
|
|
.link_close = link_close,
|
|
.complete = prov_complete,
|
|
.reset = prov_reset,
|
|
};
|
|
|
|
/*********************************************************************
|
|
* GLOBAL TYPEDEFS
|
|
*/
|
|
|
|
/*********************************************************************
|
|
* @fn silen_adv_set
|
|
*
|
|
* @brief 设置静默广播
|
|
*
|
|
* @param flag - 0(处于未配网广播状态),1(处于静默广播状态).
|
|
*
|
|
* @return none
|
|
*/
|
|
static void silen_adv_set(uint8_t flag)
|
|
{
|
|
tm_uuid[13] &= ~BIT(0);
|
|
tm_uuid[13] |= (BIT_MASK(1) & flag);
|
|
}
|
|
|
|
/*********************************************************************
|
|
* @fn prov_enable
|
|
*
|
|
* @brief 使能配网功能
|
|
*
|
|
* @param none
|
|
*
|
|
* @return none
|
|
*/
|
|
static void prov_enable(void)
|
|
{
|
|
silen_adv_set(SELENCE_ADV_OF);
|
|
|
|
if(bt_mesh_is_provisioned())
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Make sure we're scanning for provisioning inviations
|
|
bt_mesh_scan_enable();
|
|
// Enable unprovisioned beacon sending
|
|
bt_mesh_beacon_enable();
|
|
|
|
if(CONFIG_BLE_MESH_PB_GATT)
|
|
{
|
|
bt_mesh_proxy_prov_enable();
|
|
}
|
|
|
|
tmos_start_task(App_TaskID, APP_SILENT_ADV_EVT, ADV_TIMEOUT);
|
|
}
|
|
|
|
/*********************************************************************
|
|
* @fn link_open
|
|
*
|
|
* @brief 配网时后的link打开回调
|
|
*
|
|
* @param bearer - 当前link是PB_ADV还是PB_GATT
|
|
*
|
|
* @return none
|
|
*/
|
|
static void link_open(bt_mesh_prov_bearer_t bearer)
|
|
{
|
|
APP_DBG(" ");
|
|
|
|
tmos_stop_task(App_TaskID, APP_SILENT_ADV_EVT);
|
|
}
|
|
|
|
/*********************************************************************
|
|
* @fn link_close
|
|
*
|
|
* @brief 配网后的link关闭回调
|
|
*
|
|
* @param bearer - 当前link是PB_ADV还是PB_GATT
|
|
* @param reason - link关闭原因
|
|
*
|
|
* @return none
|
|
*/
|
|
static void link_close(bt_mesh_prov_bearer_t bearer, uint8_t reason)
|
|
{
|
|
APP_DBG("");
|
|
|
|
if(!bt_mesh_is_provisioned())
|
|
{
|
|
prov_enable();
|
|
}
|
|
else
|
|
{
|
|
/*天猫精灵不会下发Config_model_app_bind和Config_Model_Subscrption_Add消息。
|
|
IOT设备需要自行给所有Element的所有model绑定下发的AppKey,并根据产品类型为各个
|
|
model订阅相应的组播地址(具体品类组播地址请参阅各产品软件规范)。蓝牙Mesh设备
|
|
完成配网后需要进行消息上报,上报消息包括该设备所有支持的可上报的属性。*/
|
|
|
|
/* For Light Subscription group address */
|
|
root_models[2].groups[0] = (uint16_t)0xC000;
|
|
root_models[2].groups[1] = (uint16_t)0xCFFF;
|
|
bt_mesh_store_mod_sub(&root_models[2]);
|
|
|
|
root_models[2].keys[0] = (uint16_t)0x0000;
|
|
bt_mesh_store_mod_bind(&root_models[2]);
|
|
|
|
/* For Light Subscription group address */
|
|
vnd_models[0].groups[0] = (uint16_t)0xC000;
|
|
vnd_models[0].groups[1] = (uint16_t)0xCFFF;
|
|
bt_mesh_store_mod_sub(&vnd_models[0]);
|
|
|
|
vnd_models[0].keys[0] = (uint16_t)0x0000;
|
|
bt_mesh_store_mod_bind(&vnd_models[0]);
|
|
}
|
|
}
|
|
|
|
/*********************************************************************
|
|
* @fn prov_complete
|
|
*
|
|
* @brief 配网完成回调,重新开始广播
|
|
*
|
|
* @param net_idx - 网络key的index
|
|
* @param addr - 网络地址
|
|
* @param flags - 是否处于key refresh状态
|
|
* @param iv_index - 当前网络iv的index
|
|
*
|
|
* @return none
|
|
*/
|
|
static void prov_complete(uint16_t net_idx, uint16_t addr, uint8_t flags, uint32_t iv_index)
|
|
{
|
|
/* 设备上电后,如果已配网,也需要在1~10s随机间隔后上报所有支持的属性状态。 */
|
|
tmosTimer rand_timer;
|
|
APP_DBG(" ");
|
|
|
|
rand_timer = K_SECONDS(5) + (tmos_rand() % K_SECONDS(6));
|
|
tmos_start_task(App_TaskID, APP_SILENT_ADV_EVT, rand_timer);
|
|
}
|
|
|
|
/*********************************************************************
|
|
* @fn prov_reset
|
|
*
|
|
* @brief 复位配网功能回调
|
|
*
|
|
* @param none
|
|
*
|
|
* @return none
|
|
*/
|
|
static void prov_reset(void)
|
|
{
|
|
APP_DBG("");
|
|
|
|
prov_enable();
|
|
}
|
|
|
|
/*********************************************************************
|
|
* @fn ind_end_cb
|
|
*
|
|
* @brief 发送复位事件完成回调
|
|
*
|
|
* @param err - 错误码
|
|
* @param cb_data - 回调参数
|
|
*
|
|
* @return none
|
|
*/
|
|
static void ind_end_cb(int err, void *cb_data)
|
|
{
|
|
APP_DBG(" bt_mesh_reset ");
|
|
bt_mesh_reset();
|
|
}
|
|
|
|
static const struct bt_adv_ind_send_cb reset_cb = {
|
|
.end = ind_end_cb,
|
|
};
|
|
|
|
/*********************************************************************
|
|
* @fn send_support_attr
|
|
*
|
|
* @brief 发送所有支持的可上报的属性给天猫精灵,此消息决定天猫精灵判断设备支持那些功能
|
|
*
|
|
* @param none
|
|
*
|
|
* @return none
|
|
*/
|
|
void send_support_attr(void)
|
|
{
|
|
struct bt_mesh_indicate *ind;
|
|
APP_DBG("");
|
|
|
|
if(!bt_mesh_is_provisioned())
|
|
{
|
|
APP_DBG("Local Dev Unprovisioned");
|
|
return;
|
|
}
|
|
|
|
ind = bt_mesh_ind_alloc(32);
|
|
if(!ind)
|
|
{
|
|
APP_DBG("Unable allocate buffers");
|
|
return;
|
|
}
|
|
ind->param.trans_cnt = 0x09;
|
|
ind->param.period = K_MSEC(300);
|
|
ind->param.send_ttl = BLE_MESH_TTL_DEFAULT;
|
|
ind->param.tid = als_avail_tid_get();
|
|
|
|
/* Init indication opcode */
|
|
bt_mesh_model_msg_init(&(ind->buf->b), OP_VENDOR_MESSAGE_ATTR_INDICATION);
|
|
|
|
/* Add tid field */
|
|
net_buf_simple_add_u8(&(ind->buf->b), ind->param.tid);
|
|
|
|
// 添加开关属性
|
|
{
|
|
/* Add generic onoff attrbute op */
|
|
net_buf_simple_add_le16(&(ind->buf->b), ALI_GEN_ATTR_TYPE_POWER_STATE);
|
|
|
|
/* Add current generic onoff status */
|
|
net_buf_simple_add_u8(&(ind->buf->b), read_led_state(MSG_PIN));
|
|
}
|
|
// // 可选根据阿里云设置的产品属性功能添加对应属性 ( BLE_MESH_MODEL_OP_LIGHT_LIGHTNESS_SET )
|
|
// // 这里添加亮度属性留作参考,还需要添加对应的opcode处理函数,添加方式参考开关属性的 gen_onoff_op 结构
|
|
// {
|
|
// /* Add brightness attrbute opcode */
|
|
// net_buf_simple_add_le16(&(ind->buf->b), ALI_GEN_ATTR_TYPE_BRIGHTNESS);
|
|
|
|
// /* Add brightness status (655~65535对应天猫控制1~100) */
|
|
// net_buf_simple_add_le16(&(ind->buf->b), 65535);
|
|
// }
|
|
|
|
bt_mesh_indicate_send(ind);
|
|
}
|
|
|
|
/*********************************************************************
|
|
* @fn send_led_state
|
|
*
|
|
* @brief 发送当前灯的状态给天猫精灵
|
|
*
|
|
* @param none
|
|
*
|
|
* @return none
|
|
*/
|
|
void send_led_state(void)
|
|
{
|
|
APP_DBG("");
|
|
struct indicate_param param = {
|
|
.trans_cnt = 0x09,
|
|
.period = K_MSEC(300),
|
|
.send_ttl = BLE_MESH_TTL_DEFAULT,
|
|
.tid = als_avail_tid_get(),
|
|
};
|
|
|
|
toggle_led_state(MSG_PIN);
|
|
|
|
if(!bt_mesh_is_provisioned())
|
|
{
|
|
APP_DBG("Local Dev Unprovisioned");
|
|
return;
|
|
}
|
|
|
|
send_led_indicate(¶m);
|
|
}
|
|
|
|
/*********************************************************************
|
|
* @fn send_reset_indicate
|
|
*
|
|
* @brief 发送复位事件给天猫精灵,发送完成后将清除配网状态,重置自身mesh网络
|
|
*
|
|
* @param none
|
|
*
|
|
* @return none
|
|
*/
|
|
void send_reset_indicate(void)
|
|
{
|
|
struct bt_mesh_indicate *ind;
|
|
APP_DBG("");
|
|
|
|
if(!bt_mesh_is_provisioned())
|
|
{
|
|
APP_DBG("Local Dev Unprovisioned");
|
|
return;
|
|
}
|
|
|
|
ind = bt_mesh_ind_alloc(16);
|
|
if(!ind)
|
|
{
|
|
APP_DBG("Unable allocate buffers");
|
|
return;
|
|
}
|
|
ind->param.trans_cnt = 0x09;
|
|
ind->param.period = K_MSEC(300);
|
|
ind->param.cb = &reset_cb;
|
|
ind->param.send_ttl = BLE_MESH_TTL_DEFAULT;
|
|
ind->param.tid = als_avail_tid_get();
|
|
|
|
/* Init indication opcode */
|
|
bt_mesh_model_msg_init(&(ind->buf->b), OP_VENDOR_MESSAGE_ATTR_INDICATION);
|
|
|
|
/* Add tid field */
|
|
net_buf_simple_add_u8(&(ind->buf->b), ind->param.tid);
|
|
|
|
/* Add event report opcode */
|
|
net_buf_simple_add_le16(&(ind->buf->b), ALI_GEN_ATTR_TYPE_EVENT_TRIGGER);
|
|
|
|
/* Add reset event */
|
|
net_buf_simple_add_u8(&(ind->buf->b), ALI_GEN_ATTR_TYPE_HARDWARE_RESET);
|
|
|
|
bt_mesh_indicate_send(ind);
|
|
}
|
|
|
|
#define HAL_KEY_SEND_MSG BIT(0)
|
|
#define HAL_KEY_RESET BIT(1)
|
|
|
|
/*********************************************************************
|
|
* @fn keyPress
|
|
*
|
|
* @brief 按键回调
|
|
*
|
|
* @param keys - 按键类型
|
|
*
|
|
* @return none
|
|
*/
|
|
void keyPress(uint8_t keys)
|
|
{
|
|
APP_DBG("keys : %d ", keys);
|
|
|
|
switch(keys)
|
|
{
|
|
case HAL_KEY_SEND_MSG:
|
|
send_led_state();
|
|
break;
|
|
case HAL_KEY_RESET:
|
|
send_reset_indicate();
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*********************************************************************
|
|
* @fn app_silent_adv
|
|
*
|
|
* @brief 超时后如果还未配网成功,则进入静默广播模式,若已配网,发送支持的属性给天猫精灵
|
|
*
|
|
* @param none
|
|
*
|
|
* @return none
|
|
*/
|
|
static void app_silent_adv(void)
|
|
{
|
|
APP_DBG("");
|
|
if(bt_mesh_is_provisioned())
|
|
{
|
|
send_support_attr();
|
|
return;
|
|
}
|
|
|
|
silen_adv_set(SELENCE_ADV_ON);
|
|
|
|
/* Disable Scanner not response Provisioner message */
|
|
bt_mesh_scan_disable();
|
|
}
|
|
|
|
/*********************************************************************
|
|
* @fn blemesh_on_sync
|
|
*
|
|
* @brief 同步mesh参数,启用对应功能,不建议修改
|
|
*
|
|
* @param none
|
|
*
|
|
* @return none
|
|
*/
|
|
void blemesh_on_sync(void)
|
|
{
|
|
int err;
|
|
mem_info_t info;
|
|
|
|
if(tmos_memcmp(VER_MESH_LIB, VER_MESH_FILE, strlen(VER_MESH_FILE)) == FALSE)
|
|
{
|
|
APP_DBG("head file error...\n");
|
|
while(1);
|
|
}
|
|
|
|
info.base_addr = MESH_MEM;
|
|
info.mem_len = ARRAY_SIZE(MESH_MEM);
|
|
|
|
#if(CONFIG_BLE_MESH_FRIEND)
|
|
friend_init_register(bt_mesh_friend_init, friend_state);
|
|
#endif /* FRIEND */
|
|
#if(CONFIG_BLE_MESH_LOW_POWER)
|
|
lpn_init_register(bt_mesh_lpn_init, lpn_state);
|
|
#endif /* LPN */
|
|
|
|
err = bt_mesh_cfg_set(&app_mesh_cfg, &app_dev, MacAddr, &info);
|
|
if(err)
|
|
{
|
|
APP_DBG("Unable set configuration (err:%d)", err);
|
|
return;
|
|
}
|
|
hal_rf_init();
|
|
err = bt_mesh_comp_register(&app_comp);
|
|
|
|
#if(CONFIG_BLE_MESH_RELAY)
|
|
bt_mesh_relay_init();
|
|
#endif /* RELAY */
|
|
#if(CONFIG_BLE_MESH_PROXY || CONFIG_BLE_MESH_PB_GATT)
|
|
#if(CONFIG_BLE_MESH_PROXY)
|
|
bt_mesh_proxy_beacon_init_register((void *)bt_mesh_proxy_beacon_init);
|
|
gatts_notify_register(bt_mesh_gatts_notify);
|
|
proxy_gatt_enable_register(bt_mesh_proxy_gatt_enable);
|
|
#endif /* PROXY */
|
|
#if(CONFIG_BLE_MESH_PB_GATT)
|
|
proxy_prov_enable_register(bt_mesh_proxy_prov_enable);
|
|
#endif /* PB_GATT */
|
|
|
|
bt_mesh_proxy_init();
|
|
#endif /* PROXY || PB-GATT */
|
|
|
|
#if(CONFIG_BLE_MESH_PROXY_CLI)
|
|
bt_mesh_proxy_client_init(cli); //待添加
|
|
#endif /* PROXY_CLI */
|
|
|
|
bt_mesh_prov_retransmit_init();
|
|
#if(!CONFIG_BLE_MESH_PB_GATT)
|
|
adv_link_rx_buf_register(&rx_buf);
|
|
#endif /* !PB_GATT */
|
|
err = bt_mesh_prov_init(&app_prov);
|
|
|
|
bt_mesh_mod_init();
|
|
bt_mesh_net_init();
|
|
bt_mesh_trans_init();
|
|
bt_mesh_beacon_init();
|
|
|
|
bt_mesh_adv_init();
|
|
|
|
#if((CONFIG_BLE_MESH_PB_GATT) || (CONFIG_BLE_MESH_PROXY) || (CONFIG_BLE_MESH_OTA))
|
|
bt_mesh_conn_adv_init();
|
|
#endif /* PROXY || PB-GATT || OTA */
|
|
|
|
#if(CONFIG_BLE_MESH_SETTINGS)
|
|
bt_mesh_settings_init();
|
|
#endif /* SETTINGS */
|
|
|
|
#if(CONFIG_BLE_MESH_PROXY_CLI)
|
|
bt_mesh_proxy_cli_adapt_init();
|
|
#endif /* PROXY_CLI */
|
|
|
|
#if((CONFIG_BLE_MESH_PROXY) || (CONFIG_BLE_MESH_PB_GATT) || \
|
|
(CONFIG_BLE_MESH_PROXY_CLI) || (CONFIG_BLE_MESH_OTA))
|
|
bt_mesh_adapt_init();
|
|
#endif /* PROXY || PB-GATT || PROXY_CLI || OTA */
|
|
|
|
if(err)
|
|
{
|
|
APP_DBG("Initializing mesh failed (err %d)", err);
|
|
return;
|
|
}
|
|
|
|
APP_DBG("Bluetooth initialized");
|
|
|
|
#if(CONFIG_BLE_MESH_SETTINGS)
|
|
settings_load();
|
|
#endif /* SETTINGS */
|
|
|
|
if(bt_mesh_is_provisioned())
|
|
{
|
|
APP_DBG("Mesh network restored from flash");
|
|
}
|
|
else
|
|
{
|
|
prov_enable();
|
|
}
|
|
|
|
APP_DBG("Mesh initialized");
|
|
}
|
|
|
|
/*********************************************************************
|
|
* @fn App_Init
|
|
*
|
|
* @brief 应用层初始化
|
|
*
|
|
* @return none
|
|
*/
|
|
void App_Init(void)
|
|
{
|
|
App_TaskID = TMOS_ProcessEventRegister(App_ProcessEvent);
|
|
|
|
als_vendor_init(vnd_models);
|
|
blemesh_on_sync();
|
|
HAL_KeyInit();
|
|
HalKeyConfig(keyPress);
|
|
set_led_state(MSG_PIN, 0);
|
|
}
|
|
|
|
/*********************************************************************
|
|
* @fn App_ProcessEvent
|
|
*
|
|
* @brief 应用层事件处理函数
|
|
*
|
|
* @param task_id - The TMOS assigned task ID.
|
|
* @param events - events to process. This is a bit map and can
|
|
* contain more than one event.
|
|
*
|
|
* @return events not processed
|
|
*/
|
|
static uint16_t App_ProcessEvent(uint8_t task_id, uint16_t events)
|
|
{
|
|
if(events & APP_SILENT_ADV_EVT)
|
|
{
|
|
app_silent_adv();
|
|
return (events ^ APP_SILENT_ADV_EVT);
|
|
}
|
|
|
|
// Discard unknown events
|
|
return 0;
|
|
}
|
|
|
|
/******************************** endfile @ main ******************************/
|