2026-07-17 09:08:53 +08:00
|
|
|
|
#include "app_manager.h"
|
|
|
|
|
|
#include "xtell.h"
|
|
|
|
|
|
#include "ui.h"
|
|
|
|
|
|
#include "rgb.h"
|
|
|
|
|
|
#include "event.h"
|
|
|
|
|
|
#include "system.h"
|
|
|
|
|
|
#include "../Drivers/rf.h"
|
|
|
|
|
|
|
2026-07-17 09:32:44 +08:00
|
|
|
|
// 二级传感器对码菜单中,各类传感器的法语显示名称定义
|
|
|
|
|
|
char *code menu_items[5] = {
|
|
|
|
|
|
"DETEC. PORTE", // 0: 门磁探测器 (法语: 门)
|
|
|
|
|
|
"DETEC. PIR", // 1: 红外探测器
|
|
|
|
|
|
"DETEC. FUMEE", // 2: 烟雾传感器
|
|
|
|
|
|
"DETEC. GAZ", // 3: 燃气探测器
|
|
|
|
|
|
"DETEC. EAU" // 4: 水浸探测器
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2026-07-17 09:08:53 +08:00
|
|
|
|
// 外部全局变量引用
|
|
|
|
|
|
extern SystemState current_state;
|
|
|
|
|
|
extern u8 menu_select;
|
|
|
|
|
|
extern u8 captured_type;
|
|
|
|
|
|
extern volatile u16 ms_tick;
|
|
|
|
|
|
|
|
|
|
|
|
// 菜单应用私有变量
|
|
|
|
|
|
static u8 menu_level = 0; // 0-主菜单, 1-二级传感器选择菜单, 2-IPC绑定一键发射
|
|
|
|
|
|
static u16 last_bind_tx_ms = 0; // 记录上一次绑定发射的时间戳
|
|
|
|
|
|
|
2026-07-17 09:41:29 +08:00
|
|
|
|
// 引入外部时钟调节接口
|
|
|
|
|
|
extern void Start_Time_Edit(void);
|
2026-07-17 09:08:53 +08:00
|
|
|
|
|
|
|
|
|
|
// 声明本应用的生命周期回调函数
|
|
|
|
|
|
static void MenuApp_OnStart(void);
|
|
|
|
|
|
static void MenuApp_onRun(void);
|
|
|
|
|
|
static void MenuApp_onClose(void);
|
|
|
|
|
|
static EventResult MenuApp_onEvent(SystemEvent *evt);
|
|
|
|
|
|
|
|
|
|
|
|
// 实体化定义菜单应用控制块
|
|
|
|
|
|
WristbandApp menu_app = {
|
|
|
|
|
|
APP_ID_MENU,
|
|
|
|
|
|
"Menu",
|
|
|
|
|
|
MenuApp_OnStart,
|
|
|
|
|
|
MenuApp_onRun,
|
|
|
|
|
|
MenuApp_onClose,
|
|
|
|
|
|
MenuApp_onEvent
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @brief MenuApp 启动回调
|
|
|
|
|
|
*/
|
|
|
|
|
|
static void MenuApp_OnStart(void)
|
|
|
|
|
|
{
|
|
|
|
|
|
menu_level = 0;
|
|
|
|
|
|
menu_select = 0;
|
|
|
|
|
|
current_state = STATE_PAIR_MENU; // 系统运行状态设为对码配置菜单
|
|
|
|
|
|
RF_SetMode(0); // 关闭射频接收芯片,防止接收杂波干扰屏幕绘制
|
|
|
|
|
|
UI_ShowMainMenu(menu_select); // 初始化绘制一级主菜单
|
|
|
|
|
|
RGB_Send(0, 0, 0, 0, 0, 0); // 熄灭所有灯条
|
|
|
|
|
|
XTELL_LOG("[MenuApp] Started\r\n");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @brief MenuApp 轮询主回调
|
|
|
|
|
|
*/
|
|
|
|
|
|
static void MenuApp_onRun(void)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (menu_level == 2)
|
|
|
|
|
|
{
|
|
|
|
|
|
// ====== 控制青色双灯珠同步呼吸效果 (呼吸周期 1000ms) ======
|
|
|
|
|
|
u16 breath = ms_tick % 1000;
|
|
|
|
|
|
u8 val = (breath < 500) ? (breath * 2 / 5) : ((1000 - breath) * 2 / 5); // 亮度映射 0~200
|
|
|
|
|
|
RGB_Send(0, val, val, 0, val, val); // 渲染青色 (G+B)
|
|
|
|
|
|
|
|
|
|
|
|
// ====== 控制无线发射,每 500ms 广播一次配对数据 ======
|
|
|
|
|
|
if (ms_tick - last_bind_tx_ms >= 500 || ms_tick < last_bind_tx_ms)
|
|
|
|
|
|
{
|
|
|
|
|
|
last_bind_tx_ms = ms_tick; // 备份当前时间戳
|
|
|
|
|
|
RF_SetMode(2); // 暂时切换射频芯片为发射调制模式
|
|
|
|
|
|
EV1527_Transmit(CLONED_ADDR, 0x01); // 调制发射手环克隆 ID + 绑定数据码 0x01
|
|
|
|
|
|
RF_SetMode(0); // 切回关闭状态,避免产生噪声
|
|
|
|
|
|
XTELL_LOG("[MenuApp] IPC Binding frame emitted\r\n");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @brief MenuApp 退出清理回调
|
|
|
|
|
|
*/
|
|
|
|
|
|
static void MenuApp_onClose(void)
|
|
|
|
|
|
{
|
|
|
|
|
|
menu_level = 0;
|
|
|
|
|
|
RGB_Send(0, 0, 0, 0, 0, 0); // 熄灭 RGB
|
|
|
|
|
|
RF_SetMode(1); // 重新开启无线接收模式
|
|
|
|
|
|
XTELL_LOG("[MenuApp] Closed\r\n");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @brief MenuApp 接收按键与控制事件回调
|
|
|
|
|
|
*/
|
|
|
|
|
|
static EventResult MenuApp_onEvent(SystemEvent *evt)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (menu_level == 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
// ====== 处于一级主菜单层 (0-HORLOGE, 1-APPAIRAGE, 2-LIAISON) ======
|
|
|
|
|
|
if (evt->key_event == KEY_EVENT_UP_CLICK) {
|
|
|
|
|
|
// 短按 ▲ 键向上移动焦点
|
|
|
|
|
|
if (menu_select > 0) {
|
|
|
|
|
|
menu_select--;
|
|
|
|
|
|
UI_ShowMainMenu(menu_select);
|
|
|
|
|
|
}
|
|
|
|
|
|
return EVENT_HANDLED;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (evt->key_event == KEY_EVENT_DOWN_CLICK) {
|
|
|
|
|
|
// 短按 ▼ 键向下移动焦点
|
|
|
|
|
|
if (menu_select < 2) {
|
|
|
|
|
|
menu_select++;
|
|
|
|
|
|
UI_ShowMainMenu(menu_select);
|
|
|
|
|
|
}
|
|
|
|
|
|
return EVENT_HANDLED;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (evt->key_event == KEY_EVENT_CONFIRM_CLICK) {
|
|
|
|
|
|
// 短按 ■ 确认键,进入选定功能的子页面
|
|
|
|
|
|
if (menu_select == 0) {
|
|
|
|
|
|
// 功能 1:设置时间。启动待机时钟应用,并调用微调编辑入口
|
|
|
|
|
|
AppManager_SwitchToForeground(&clock_app);
|
|
|
|
|
|
Start_Time_Edit();
|
|
|
|
|
|
} else if (menu_select == 1) {
|
|
|
|
|
|
// 功能 2:传感器学习。进入二级传感器类别选择菜单
|
|
|
|
|
|
menu_level = 1;
|
|
|
|
|
|
menu_select = 0;
|
|
|
|
|
|
UI_ShowPairMenuPage(menu_select); // 绘制二级设备分类页
|
|
|
|
|
|
} else if (menu_select == 2) {
|
|
|
|
|
|
// 功能 3:相机配对。进入摄像机一键绑定发射状态
|
|
|
|
|
|
menu_level = 2;
|
|
|
|
|
|
last_bind_tx_ms = ms_tick; // 记录初始发射时间
|
|
|
|
|
|
current_state = STATE_IPC_BIND; // 系统设为 IPC 绑定状态
|
|
|
|
|
|
UI_ShowBindingPage(CLONED_ADDR); // 绘制相机绑定信息页
|
|
|
|
|
|
}
|
|
|
|
|
|
return EVENT_HANDLED;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (evt->key_event == KEY_EVENT_CONFIRM_LONG) {
|
|
|
|
|
|
// 长按 ■ 确认键,退出设置菜单直接返回待机时钟
|
|
|
|
|
|
AppManager_SwitchToForeground(&clock_app);
|
|
|
|
|
|
return EVENT_HANDLED;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (menu_level == 1)
|
|
|
|
|
|
{
|
|
|
|
|
|
// ====== 处于二级传感器对码类型菜单层 (0-门磁, 1-PIR, 2-烟感, 3-气感, 4-水浸) ======
|
|
|
|
|
|
if (evt->key_event == KEY_EVENT_UP_CLICK) {
|
|
|
|
|
|
// 上移焦点
|
|
|
|
|
|
if (menu_select > 0) {
|
|
|
|
|
|
menu_select--;
|
|
|
|
|
|
UI_ShowPairMenuPage(menu_select);
|
|
|
|
|
|
}
|
|
|
|
|
|
return EVENT_HANDLED;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (evt->key_event == KEY_EVENT_DOWN_CLICK) {
|
|
|
|
|
|
// 下移焦点
|
|
|
|
|
|
if (menu_select < 4) {
|
|
|
|
|
|
menu_select++;
|
|
|
|
|
|
UI_ShowPairMenuPage(menu_select);
|
|
|
|
|
|
}
|
|
|
|
|
|
return EVENT_HANDLED;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (evt->key_event == KEY_EVENT_CONFIRM_CLICK) {
|
|
|
|
|
|
// 确认选择:缓存用户选好的传感器类别,短震反馈并加载对码应用 (PairApp)
|
|
|
|
|
|
captured_type = menu_select;
|
|
|
|
|
|
MOTOR = 1;
|
|
|
|
|
|
Delay_ms(100);
|
|
|
|
|
|
MOTOR = 0;
|
|
|
|
|
|
AppManager_SwitchToForeground(&pair_app); // 切换至 PairApp 对码
|
|
|
|
|
|
return EVENT_HANDLED;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (evt->key_event == KEY_EVENT_DOWN_LONG) {
|
|
|
|
|
|
// 长按 ▼ 键,从二级菜单退回到一级主菜单
|
|
|
|
|
|
menu_level = 0;
|
|
|
|
|
|
menu_select = 1; // 回到 APPAIRAGE 选项上
|
|
|
|
|
|
UI_ShowMainMenu(menu_select);
|
|
|
|
|
|
return EVENT_HANDLED;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (menu_level == 2)
|
|
|
|
|
|
{
|
|
|
|
|
|
// ====== 处于摄像机配对一键绑定发送层 ======
|
|
|
|
|
|
// 长按 ■ 确认键 或 长按 ▼ 键,均表示取消绑定,退出发射并返回一级主菜单
|
|
|
|
|
|
if (evt->key_event == KEY_EVENT_CONFIRM_LONG || evt->key_event == KEY_EVENT_DOWN_LONG) {
|
|
|
|
|
|
menu_level = 0;
|
|
|
|
|
|
menu_select = 2; // 回到 LIAISON 选项上
|
|
|
|
|
|
current_state = STATE_PAIR_MENU;
|
|
|
|
|
|
RGB_Send(0, 0, 0, 0, 0, 0); // 关闭呼吸灯
|
|
|
|
|
|
UI_ShowMainMenu(menu_select);
|
|
|
|
|
|
return EVENT_HANDLED;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return EVENT_IGNORED;
|
|
|
|
|
|
}
|