优化BLE断连后重连广播和温湿度广播切换的程序架构

This commit is contained in:
2026-09-03 15:31:40 +08:00
parent e68670df92
commit 408c25bd5c
7 changed files with 294 additions and 189 deletions
+2 -2
View File
@@ -67,10 +67,10 @@ uint8_t app_th_is_fault(void);
uint8_t app_th_last_sample_ok(void);
/**
* @brief 取走一次「本周期采样成功」事件(供 usr_le_adv 的 500ms 任务上下文)
* @brief 取走一次「本周期采样成功」事件(供 app_th_adv 的 500ms 任务上下文)
* @note ⚠ 生产者是 app_th_poll(20ms 硬件定时器中断上下文),那里只置
* volatile pending,不开关广播、不打日志、不写 flash。
* 消费者(usr_ble_adv_updataBLE 线程任务上下文)调本函数取走,
* 消费者(app_th_adv_tick,由 usr_ble_adv_updata 调用)调本函数取走,
* 内部 local_irq_disable 保护,取到即清。
* 只在真正采样成功(last_ok 那次)时产生,失败/fault 不产生,
* 温度、湿度都是对外值(与数码管/DP3/DP4 一致)。
+206
View File
@@ -0,0 +1,206 @@
/******************************************************************************
* @file app_th_adv.c
* @brief CBR3 自定义温湿度广播窗实现
* @author cyWu <1917507415@qq.com>
* @date 2026.09.03
* @version V1.0.0
* @history
* - V1.0.0, 2026.09.03, cyWu, 从 usr_le_adv.c 拆出
******************************************************************************/
#include "app_th_adv.h"
#include "app_th.h"
#include "app_linkage.h"
#include "board_pin.h"
#include "usr_le_api.h"
#include "system/includes.h"
#include "app_main.h"
#define LOG_TAG_CONST APP
#define LOG_TAG "[TH_ADV]"
#define LOG_INFO_ENABLE
#include "debug.h"
extern void usr_set_adv_interval(u16 val);
extern u16 usr_get_adv_interval(void);
#define TH_ADV_DATA_MAX 31
#define TH_ADV_WINDOW_TICKS 2 /**< 500ms × 2 = 1s */
#define TH_ADV_FAST_INTERVAL 80 /**< 窗内快广播,暂停 60s 变慢 */
#define TH_ADV_TYPE_FLAGS 0x01
#define TH_ADV_TYPE_LOCAL_NAME 0x09
#define TH_ADV_TYPE_MANUFACTURER 0xFF
typedef struct {
uint8_t ticks; /**< >0 = 窗进行中,剩余 500ms 拍数 */
uint16_t interval; /**< 进窗前提速前的间隔;0=进窗前已是快广播 */
} AppThAdvCtx_t;
static AppThAdvCtx_t s_th_adv;
/**
* @brief 配对 / OTA / 已连接 / 未配网 → 不允许发温湿度窗
* @return 1=阻塞,0=允许
*/
static uint8_t th_adv_blocked(void)
{
if (usr_ble_is_connected()) {
return 1;
}
if (usr_var.usr_goto_pair || usr_var.usr_goto_updata ||
usr_var.usr_ota_succ_flag) {
return 1;
}
if (usr_get_pair_flag() == 0) {
return 1;
}
return 0;
}
/**
* @brief 组自定义温湿度 ADFlags + Complete Local Name + Manufacturer 0xFFFF
* @param tank 缸体编号(非 0)
* @param ver 配置版本
* @param temp_x10 对外温度 ×10
* @param humi 对外湿度 %
* @return 无
*/
static void th_adv_encode(uint16_t tank, uint8_t ver, int16_t temp_x10, uint8_t humi)
{
uint8_t buf[TH_ADV_DATA_MAX];
uint8_t *p = buf;
char dec[5];
uint8_t digits = 0;
uint16_t v = tank;
int32_t t_int;
uint8_t name_len;
*p++ = 0x02;
*p++ = TH_ADV_TYPE_FLAGS;
*p++ = 0x06;
while (v) {
dec[digits++] = (char)('0' + (v % 10));
v /= 10;
}
name_len = (uint8_t)(5 + digits); /* "JBao-" + tank 位数 */
*p++ = (uint8_t)(1 + name_len);
*p++ = TH_ADV_TYPE_LOCAL_NAME;
*p++ = 'J';
*p++ = 'B';
*p++ = 'a';
*p++ = 'o';
*p++ = '-';
while (digits) {
*p++ = (uint8_t)dec[--digits];
}
t_int = temp_x10 / 10;
if (t_int < -128) {
t_int = -128;
}
if (t_int > 127) {
t_int = 127;
}
if (humi > 100) {
humi = 100;
}
*p++ = 0x06;
*p++ = TH_ADV_TYPE_MANUFACTURER;
*p++ = 0xFF;
*p++ = 0xFF;
*p++ = ver;
*p++ = (uint8_t)t_int;
*p++ = humi;
usr_ble_adv_set_raw(buf, (uint8_t)(p - buf));
}
/**
* @brief 结束温湿度窗:还原广播间隔,可选切回见宝回连
* @param back_to_reconn 1=组回连包(窗自然到期);0=只清窗
* @return 无
*/
static void th_adv_stop(uint8_t back_to_reconn)
{
if (s_th_adv.ticks == 0) {
return;
}
s_th_adv.ticks = 0;
if (s_th_adv.interval != 0) {
usr_set_adv_interval(s_th_adv.interval);
s_th_adv.interval = 0;
}
if (back_to_reconn) {
usr_ble_adv_encode_reconn();
log_info("th adv win end, back to reconn\n");
}
}
/**
* @brief 丢掉温湿度窗(不组回连包)
* @return 无
*/
void app_th_adv_reset(void)
{
s_th_adv.ticks = 0;
s_th_adv.interval = 0;
}
/**
* @brief 温湿度窗是否占用广播
* @return 1=窗进行中,0=空闲
*/
uint8_t app_th_adv_is_active(void)
{
return (s_th_adv.ticks != 0) ? 1 : 0;
}
/**
* @brief 温湿度窗状态机(500ms 一拍)
* @return 无
*/
void app_th_adv_tick(void)
{
#if !BOARD_TH_ENABLE
return;
#else
int16_t t_x10 = 0;
uint8_t humi = 0;
uint16_t tank;
if (s_th_adv.ticks) {
if (th_adv_blocked()) {
th_adv_stop(0);
} else if (s_th_adv.ticks > 1) {
s_th_adv.ticks--;
} else {
/* 最后一拍必须先 stop(里头要求 ticks!=0),再组回连包 */
th_adv_stop(1);
}
}
if (th_adv_blocked()) {
return;
}
if (!app_th_take_sample(&t_x10, &humi)) {
return;
}
tank = app_linkage_get_tank_id();
if (tank == 0) {
return;
}
if (s_th_adv.ticks == 0) {
s_th_adv.interval = (usr_get_adv_interval() != TH_ADV_FAST_INTERVAL) ?
usr_get_adv_interval() : 0;
usr_set_adv_interval(TH_ADV_FAST_INTERVAL);
}
th_adv_encode(tank, app_linkage_get_cfg_ver(), t_x10, humi);
s_th_adv.ticks = TH_ADV_WINDOW_TICKS;
log_info("th adv: tank=%u ver=%u T=%dC H=%u%%\n",
tank, app_linkage_get_cfg_ver(), (int)(t_x10 / 10), humi);
#endif
}
+41
View File
@@ -0,0 +1,41 @@
/******************************************************************************
* @file app_th_adv.h
* @brief CBR3 自定义温湿度广播窗(已绑定未连接时插 1s,再切回见宝回连)
* @author cyWu <1917507415@qq.com>
* @date 2026.09.03
* @version V1.0.0
* @history
* - V1.0.0, 2026.09.03, cyWu, 从 usr_le_adv.c 拆出
*
* @note 给 nRF / 自研扫描器看,不是见宝 TLV。GATT 0x2A00 不动。
* 进窗条件:未连接 + 已配网 + 非配对 + 非 OTA + tank_id≠0
* + 本周期 AHT20 采样成功。窗长 500ms × 2。
* ⚠ 只在 usr_ble_adv_updata500ms 任务上下文)里 tick
* app_th 中断侧只置 pending,本模块是唯一消费者。
******************************************************************************/
#ifndef __APP_TH_ADV_H__
#define __APP_TH_ADV_H__
#include <stdint.h>
/**
* @brief 丢掉温湿度窗(不组回连包)
* @note usr_ble_adv_init 会自己组绑定/回连,进 init 前调本函数清窗即可
* @return 无
*/
void app_th_adv_reset(void);
/**
* @brief 温湿度窗状态机(500ms 一拍,须在写协议栈广播数据之前调用)
* @return 无
*/
void app_th_adv_tick(void);
/**
* @brief 温湿度窗是否占用广播
* @return 1=窗进行中(暂停 60s 变慢广播),0=空闲
*/
uint8_t app_th_adv_is_active(void);
#endif /* __APP_TH_ADV_H__ */