784 lines
24 KiB
C
784 lines
24 KiB
C
|
|
#include "app_manager.h"
|
|||
|
|
#include "rgb.h"
|
|||
|
|
#include "event.h"
|
|||
|
|
#include "database.h"
|
|||
|
|
#include "ui.h"
|
|||
|
|
#include "system.h"
|
|||
|
|
#include "../Drivers/rf.h"
|
|||
|
|
#include "../Drivers/lcd.h"
|
|||
|
|
|
|||
|
|
#define APP_ONRUN_MAX_TICKS 5
|
|||
|
|
|
|||
|
|
// 定义局部静态注册表
|
|||
|
|
static WristbandApp app_registry[APP_ID_MAX];
|
|||
|
|
static WristbandApp *active_app = NULL;
|
|||
|
|
#define DEFAULT_APP_ID APP_ID_CLOCK
|
|||
|
|
|
|||
|
|
// 定义菜单项定义
|
|||
|
|
char *code menu_items[5] = {
|
|||
|
|
"DETEC. PORTE",
|
|||
|
|
"DETEC. PIR",
|
|||
|
|
"DETEC. FUMEE",
|
|||
|
|
"DETEC. GAZ",
|
|||
|
|
"DETEC. EAU"
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
/* 回调函数前置声明 */
|
|||
|
|
void ClockApp_OnStart(void);
|
|||
|
|
void ClockApp_onRun(void);
|
|||
|
|
void ClockApp_onClose(void);
|
|||
|
|
EventResult ClockApp_onEvent(SystemEvent *evt);
|
|||
|
|
|
|||
|
|
void MenuApp_OnStart(void);
|
|||
|
|
void MenuApp_onRun(void);
|
|||
|
|
void MenuApp_onClose(void);
|
|||
|
|
EventResult MenuApp_onEvent(SystemEvent *evt);
|
|||
|
|
|
|||
|
|
void PairApp_OnStart(void);
|
|||
|
|
void PairApp_onRun(void);
|
|||
|
|
void PairApp_onClose(void);
|
|||
|
|
EventResult PairApp_onEvent(SystemEvent *evt);
|
|||
|
|
|
|||
|
|
void AlarmApp_OnStart(void);
|
|||
|
|
void AlarmApp_onRun(void);
|
|||
|
|
void AlarmApp_onClose(void);
|
|||
|
|
EventResult AlarmApp_onEvent(SystemEvent *evt);
|
|||
|
|
|
|||
|
|
void SOSApp_OnStart(void);
|
|||
|
|
void SOSApp_onRun(void);
|
|||
|
|
void SOSApp_onClose(void);
|
|||
|
|
EventResult SOSApp_onEvent(SystemEvent *evt);
|
|||
|
|
|
|||
|
|
/* ====== AppManager 核心接口 ====== */
|
|||
|
|
|
|||
|
|
void AppManager_Init(void)
|
|||
|
|
{
|
|||
|
|
u8 i;
|
|||
|
|
/* 清零注册表 */
|
|||
|
|
for (i = 0; i < APP_ID_MAX; i++) {
|
|||
|
|
app_registry[i].app_id = APP_ID_MAX;
|
|||
|
|
app_registry[i].app_type = APP_TYPE_FOREGROUND;
|
|||
|
|
app_registry[i].app_name = "";
|
|||
|
|
app_registry[i].OnStart = NULL;
|
|||
|
|
app_registry[i].onRun = NULL;
|
|||
|
|
app_registry[i].onClose = NULL;
|
|||
|
|
app_registry[i].onEvent = NULL;
|
|||
|
|
app_registry[i].is_active = 0;
|
|||
|
|
app_registry[i].is_running = 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* 注册 ClockApp */
|
|||
|
|
app_registry[APP_ID_CLOCK].app_id = APP_ID_CLOCK;
|
|||
|
|
app_registry[APP_ID_CLOCK].app_type = APP_TYPE_FOREGROUND;
|
|||
|
|
app_registry[APP_ID_CLOCK].app_name = "Clock";
|
|||
|
|
app_registry[APP_ID_CLOCK].OnStart = ClockApp_OnStart;
|
|||
|
|
app_registry[APP_ID_CLOCK].onRun = ClockApp_onRun;
|
|||
|
|
app_registry[APP_ID_CLOCK].onClose = ClockApp_onClose;
|
|||
|
|
app_registry[APP_ID_CLOCK].onEvent = ClockApp_onEvent;
|
|||
|
|
|
|||
|
|
/* 注册 MenuApp */
|
|||
|
|
app_registry[APP_ID_MENU].app_id = APP_ID_MENU;
|
|||
|
|
app_registry[APP_ID_MENU].app_type = APP_TYPE_FOREGROUND;
|
|||
|
|
app_registry[APP_ID_MENU].app_name = "Menu";
|
|||
|
|
app_registry[APP_ID_MENU].OnStart = MenuApp_OnStart;
|
|||
|
|
app_registry[APP_ID_MENU].onRun = MenuApp_onRun;
|
|||
|
|
app_registry[APP_ID_MENU].onClose = MenuApp_onClose;
|
|||
|
|
app_registry[APP_ID_MENU].onEvent = MenuApp_onEvent;
|
|||
|
|
|
|||
|
|
/* 注册 PairApp */
|
|||
|
|
app_registry[APP_ID_PAIR].app_id = APP_ID_PAIR;
|
|||
|
|
app_registry[APP_ID_PAIR].app_type = APP_TYPE_FOREGROUND;
|
|||
|
|
app_registry[APP_ID_PAIR].app_name = "Pair";
|
|||
|
|
app_registry[APP_ID_PAIR].OnStart = PairApp_OnStart;
|
|||
|
|
app_registry[APP_ID_PAIR].onRun = PairApp_onRun;
|
|||
|
|
app_registry[APP_ID_PAIR].onClose = PairApp_onClose;
|
|||
|
|
app_registry[APP_ID_PAIR].onEvent = PairApp_onEvent;
|
|||
|
|
|
|||
|
|
/* 注册 AlarmApp */
|
|||
|
|
app_registry[APP_ID_ALARM].app_id = APP_ID_ALARM;
|
|||
|
|
app_registry[APP_ID_ALARM].app_type = APP_TYPE_FOREGROUND;
|
|||
|
|
app_registry[APP_ID_ALARM].app_name = "Alarm";
|
|||
|
|
app_registry[APP_ID_ALARM].OnStart = AlarmApp_OnStart;
|
|||
|
|
app_registry[APP_ID_ALARM].onRun = AlarmApp_onRun;
|
|||
|
|
app_registry[APP_ID_ALARM].onClose = AlarmApp_onClose;
|
|||
|
|
app_registry[APP_ID_ALARM].onEvent = AlarmApp_onEvent;
|
|||
|
|
|
|||
|
|
/* 注册 SOSApp */
|
|||
|
|
app_registry[APP_ID_SOS].app_id = APP_ID_SOS;
|
|||
|
|
app_registry[APP_ID_SOS].app_type = APP_TYPE_FOREGROUND;
|
|||
|
|
app_registry[APP_ID_SOS].app_name = "SOS";
|
|||
|
|
app_registry[APP_ID_SOS].OnStart = SOSApp_OnStart;
|
|||
|
|
app_registry[APP_ID_SOS].onRun = SOSApp_onRun;
|
|||
|
|
app_registry[APP_ID_SOS].onClose = SOSApp_onClose;
|
|||
|
|
app_registry[APP_ID_SOS].onEvent = SOSApp_onEvent;
|
|||
|
|
|
|||
|
|
AppManager_StartApp(DEFAULT_APP_ID);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void AppManager_StartApp(AppID app_id)
|
|||
|
|
{
|
|||
|
|
WristbandApp *target;
|
|||
|
|
if (app_id >= APP_ID_MAX) return;
|
|||
|
|
target = &app_registry[app_id];
|
|||
|
|
if (target->OnStart == NULL) return;
|
|||
|
|
if (active_app == target) return;
|
|||
|
|
|
|||
|
|
Uart_SendString("[APP] StartApp: ");
|
|||
|
|
Uart_SendString(target->app_name);
|
|||
|
|
Uart_SendString("\r\n");
|
|||
|
|
|
|||
|
|
/* 关闭当前活跃应用 */
|
|||
|
|
if (active_app != NULL && active_app->onClose != NULL) {
|
|||
|
|
active_app->is_active = 0;
|
|||
|
|
active_app->onClose();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* 切换并启动新应用 */
|
|||
|
|
active_app = target;
|
|||
|
|
if (active_app->OnStart != NULL) {
|
|||
|
|
active_app->is_active = 1;
|
|||
|
|
active_app->is_running = 1;
|
|||
|
|
active_app->OnStart();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void AppManager_DispatchEvent(SystemEvent evt)
|
|||
|
|
{
|
|||
|
|
EventResult result = EVENT_IGNORED;
|
|||
|
|
if (active_app != NULL && active_app->is_active && active_app->onEvent != NULL) {
|
|||
|
|
result = active_app->onEvent(&evt);
|
|||
|
|
if (result == EVENT_HANDLED) return;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void AppManager_RunActiveApp(void)
|
|||
|
|
{
|
|||
|
|
u16 start_tick;
|
|||
|
|
u16 elapsed;
|
|||
|
|
if (active_app == NULL || !active_app->is_active) return;
|
|||
|
|
if (!active_app->is_running) return;
|
|||
|
|
if (active_app->onRun == NULL) return;
|
|||
|
|
start_tick = ms_tick;
|
|||
|
|
active_app->onRun();
|
|||
|
|
elapsed = ms_tick - start_tick;
|
|||
|
|
if (elapsed > APP_ONRUN_MAX_TICKS) {
|
|||
|
|
active_app->is_running = 0;
|
|||
|
|
} else {
|
|||
|
|
active_app->is_running = 1;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
AppID AppManager_GetActiveAppID(void)
|
|||
|
|
{
|
|||
|
|
if (active_app == NULL) return APP_ID_MAX;
|
|||
|
|
return active_app->app_id;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
/* =========================================================================
|
|||
|
|
* ClockApp 回调实现与时间编辑状态机
|
|||
|
|
* ========================================================================= */
|
|||
|
|
|
|||
|
|
static u8 time_edit_active = 0;
|
|||
|
|
static u8 time_edit_field = 1;
|
|||
|
|
static u8 time_edit_blink_on = 1;
|
|||
|
|
|
|||
|
|
void Start_Time_Edit(void)
|
|||
|
|
{
|
|||
|
|
time_edit_active = 1;
|
|||
|
|
time_edit_field = 1;
|
|||
|
|
time_edit_blink_on = 1;
|
|||
|
|
current_state = STATE_SET_TIME;
|
|||
|
|
|
|||
|
|
// FCOB 幻彩灯条蓝色常亮 (R=0, G=0, B=180)
|
|||
|
|
RGB_Send(0, 0, 180, 0, 0, 180);
|
|||
|
|
|
|||
|
|
// 马达短振 50ms
|
|||
|
|
MOTOR = 1;
|
|||
|
|
Delay_ms(50);
|
|||
|
|
MOTOR = 0;
|
|||
|
|
|
|||
|
|
UI_ShowSetTimePage(current_hour, current_min, time_edit_field, 1);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void ClockApp_OnStart(void)
|
|||
|
|
{
|
|||
|
|
time_edit_active = 0;
|
|||
|
|
current_state = STATE_NORMAL;
|
|||
|
|
RF_SetMode(1);
|
|||
|
|
UI_ShowClockPage(current_state, current_hour, current_min);
|
|||
|
|
|
|||
|
|
// 启动时熄灭灯条
|
|||
|
|
RGB_Send(0, 0, 0, 0, 0, 0);
|
|||
|
|
|
|||
|
|
Uart_SendString("[ClockApp] Started\r\n");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void ClockApp_onRun(void)
|
|||
|
|
{
|
|||
|
|
u32 rx_addr;
|
|||
|
|
u8 rx_data;
|
|||
|
|
|
|||
|
|
if (time_edit_active)
|
|||
|
|
{
|
|||
|
|
// 500ms 周期控制闪烁
|
|||
|
|
u8 blink = (ms_tick / 500) % 2;
|
|||
|
|
if (blink != time_edit_blink_on)
|
|||
|
|
{
|
|||
|
|
time_edit_blink_on = blink;
|
|||
|
|
UI_ShowSetTimePage(current_hour, current_min, time_edit_field, time_edit_blink_on);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
if (clock_updated) {
|
|||
|
|
clock_updated = 0;
|
|||
|
|
UI_ShowClockPage(current_state, current_hour, current_min);
|
|||
|
|
}
|
|||
|
|
if (EV1527_Decode(&rx_addr, &rx_data)) {
|
|||
|
|
u8 slot;
|
|||
|
|
if (Check_Sensor_ID(rx_addr, &slot)) {
|
|||
|
|
u8 sensor_type = sensor_list[slot].type;
|
|||
|
|
if (sensor_type < 5) {
|
|||
|
|
if (sensor_list[slot].zone == 0 || current_state == STATE_ARMED) {
|
|||
|
|
SystemEvent rf_evt;
|
|||
|
|
rf_evt.key_event = KEY_EVENT_NONE;
|
|||
|
|
rf_evt.priority = EVENT_PRIORITY_HIGH;
|
|||
|
|
rf_evt.extra_data = rx_addr;
|
|||
|
|
rf_evt.extra_size = 4;
|
|||
|
|
EventQueue_InsertFront(rf_evt);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void ClockApp_onClose(void)
|
|||
|
|
{
|
|||
|
|
time_edit_active = 0;
|
|||
|
|
RGB_Send(0, 0, 0, 0, 0, 0);
|
|||
|
|
Uart_SendString("[ClockApp] Closed\r\n");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
EventResult ClockApp_onEvent(SystemEvent *evt)
|
|||
|
|
{
|
|||
|
|
if (time_edit_active)
|
|||
|
|
{
|
|||
|
|
if (evt->key_event == KEY_EVENT_UP_CLICK)
|
|||
|
|
{
|
|||
|
|
if (time_edit_field == 1) {
|
|||
|
|
current_hour = (current_hour + 1) % 24;
|
|||
|
|
} else {
|
|||
|
|
current_min = (current_min + 1) % 60;
|
|||
|
|
}
|
|||
|
|
UI_ShowSetTimePage(current_hour, current_min, time_edit_field, 1);
|
|||
|
|
return EVENT_HANDLED;
|
|||
|
|
}
|
|||
|
|
if (evt->key_event == KEY_EVENT_DOWN_CLICK)
|
|||
|
|
{
|
|||
|
|
if (time_edit_field == 1) {
|
|||
|
|
current_hour = (current_hour == 0) ? 23 : (current_hour - 1);
|
|||
|
|
} else {
|
|||
|
|
current_min = (current_min == 0) ? 59 : (current_min - 1);
|
|||
|
|
}
|
|||
|
|
UI_ShowSetTimePage(current_hour, current_min, time_edit_field, 1);
|
|||
|
|
return EVENT_HANDLED;
|
|||
|
|
}
|
|||
|
|
if (evt->key_event == KEY_EVENT_CONFIRM_LONG)
|
|||
|
|
{
|
|||
|
|
// 长按 Confirm 键跳转字段
|
|||
|
|
if (time_edit_field == 1) {
|
|||
|
|
time_edit_field = 2;
|
|||
|
|
} else {
|
|||
|
|
time_edit_field = 1;
|
|||
|
|
}
|
|||
|
|
UI_ShowSetTimePage(current_hour, current_min, time_edit_field, 1);
|
|||
|
|
return EVENT_HANDLED;
|
|||
|
|
}
|
|||
|
|
if (evt->key_event == KEY_EVENT_CONFIRM_CLICK)
|
|||
|
|
{
|
|||
|
|
// 短按 Confirm 键保存退出
|
|||
|
|
time_edit_active = 0;
|
|||
|
|
current_state = STATE_NORMAL;
|
|||
|
|
RGB_Send(0, 0, 0, 0, 0, 0); // 熄灭
|
|||
|
|
|
|||
|
|
// 退出短振
|
|||
|
|
MOTOR = 1; Delay_ms(50); MOTOR = 0;
|
|||
|
|
|
|||
|
|
UI_ShowClockPage(current_state, current_hour, current_min);
|
|||
|
|
return EVENT_HANDLED;
|
|||
|
|
}
|
|||
|
|
return EVENT_HANDLED; // 吞掉其他按键
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (evt->key_event == KEY_EVENT_CONFIRM_LONG) {
|
|||
|
|
AppManager_StartApp(APP_ID_MENU);
|
|||
|
|
return EVENT_HANDLED;
|
|||
|
|
}
|
|||
|
|
if (evt->key_event == KEY_EVENT_UP_LONG) {
|
|||
|
|
if (current_state == STATE_ARMED) {
|
|||
|
|
current_state = STATE_DISARMED;
|
|||
|
|
} else {
|
|||
|
|
current_state = STATE_ARMED;
|
|||
|
|
}
|
|||
|
|
// 切换状态短震确认
|
|||
|
|
MOTOR = 1; Delay_ms(100); MOTOR = 0;
|
|||
|
|
UI_ShowClockPage(current_state, current_hour, current_min);
|
|||
|
|
return EVENT_HANDLED;
|
|||
|
|
}
|
|||
|
|
if (evt->key_event == KEY_EVENT_SOS_CLICK || evt->key_event == KEY_EVENT_SOS_LONG) {
|
|||
|
|
AppManager_StartApp(APP_ID_SOS);
|
|||
|
|
return EVENT_HANDLED;
|
|||
|
|
}
|
|||
|
|
return EVENT_IGNORED;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
/* =========================================================================
|
|||
|
|
* MenuApp 回调实现
|
|||
|
|
* ========================================================================= */
|
|||
|
|
|
|||
|
|
static u8 menu_level = 0; // 0:主菜单, 1:传感器对码二级菜单, 2:IPC绑定中
|
|||
|
|
static u16 last_bind_tx_ms = 0;
|
|||
|
|
|
|||
|
|
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); // 熄灭灯条
|
|||
|
|
Uart_SendString("[MenuApp] Started (Main Menu)\r\n");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
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);
|
|||
|
|
|
|||
|
|
// 每 500ms 发射一次绑定信号 (出厂 Factory ID)
|
|||
|
|
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);
|
|||
|
|
RF_SetMode(0);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void MenuApp_onClose(void)
|
|||
|
|
{
|
|||
|
|
menu_level = 0;
|
|||
|
|
RGB_Send(0, 0, 0, 0, 0, 0);
|
|||
|
|
RF_SetMode(1);
|
|||
|
|
Uart_SendString("[MenuApp] Closed\r\n");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
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) {
|
|||
|
|
// 启动时钟 App 并立即进入编辑模式
|
|||
|
|
AppManager_StartApp(APP_ID_CLOCK);
|
|||
|
|
Start_Time_Edit();
|
|||
|
|
} else if (menu_select == 1) {
|
|||
|
|
// 进入二级传感器对码菜单
|
|||
|
|
menu_level = 1;
|
|||
|
|
menu_select = 0;
|
|||
|
|
UI_ShowPairMenuPage(menu_select);
|
|||
|
|
} else if (menu_select == 2) {
|
|||
|
|
// 进入摄像机绑定
|
|||
|
|
menu_level = 2;
|
|||
|
|
last_bind_tx_ms = ms_tick;
|
|||
|
|
current_state = STATE_IPC_BIND;
|
|||
|
|
UI_ShowBindingPage(CLONED_ADDR);
|
|||
|
|
}
|
|||
|
|
return EVENT_HANDLED;
|
|||
|
|
}
|
|||
|
|
if (evt->key_event == KEY_EVENT_CONFIRM_LONG) {
|
|||
|
|
AppManager_StartApp(APP_ID_CLOCK);
|
|||
|
|
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) {
|
|||
|
|
// 保存当前选定的类型到 captured_type,短震 100ms 并跳转到 PairApp 对码搜索
|
|||
|
|
captured_type = menu_select;
|
|||
|
|
MOTOR = 1;
|
|||
|
|
Delay_ms(100);
|
|||
|
|
MOTOR = 0;
|
|||
|
|
AppManager_StartApp(APP_ID_PAIR);
|
|||
|
|
return EVENT_HANDLED;
|
|||
|
|
}
|
|||
|
|
if (evt->key_event == KEY_EVENT_DOWN_LONG) {
|
|||
|
|
// 返回主菜单
|
|||
|
|
menu_level = 0;
|
|||
|
|
menu_select = 1;
|
|||
|
|
UI_ShowMainMenu(menu_select);
|
|||
|
|
return EVENT_HANDLED;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else if (menu_level == 2)
|
|||
|
|
{
|
|||
|
|
// 绑定中:长按 Confirm 键 (3秒) 或 长按 DOWN 键 (2秒) 退出返回主菜单
|
|||
|
|
if (evt->key_event == KEY_EVENT_CONFIRM_LONG || evt->key_event == KEY_EVENT_DOWN_LONG) {
|
|||
|
|
menu_level = 0;
|
|||
|
|
menu_select = 2;
|
|||
|
|
current_state = STATE_PAIR_MENU;
|
|||
|
|
RGB_Send(0, 0, 0, 0, 0, 0); // 熄灭
|
|||
|
|
UI_ShowMainMenu(menu_select);
|
|||
|
|
return EVENT_HANDLED;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return EVENT_IGNORED;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
/* =========================================================================
|
|||
|
|
* PairApp 回调实现
|
|||
|
|
* ========================================================================= */
|
|||
|
|
|
|||
|
|
enum {
|
|||
|
|
PAIR_STATE_WAIT,
|
|||
|
|
PAIR_STATE_CONFIRM,
|
|||
|
|
PAIR_STATE_SUCCESS,
|
|||
|
|
PAIR_STATE_FAIL
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
static u8 pair_state;
|
|||
|
|
static u8 last_radar_sec;
|
|||
|
|
static u8 captured_zone = 1;
|
|||
|
|
static u32 success_start_ms = 0;
|
|||
|
|
static u32 fail_start_ms = 0;
|
|||
|
|
|
|||
|
|
void PairApp_OnStart(void)
|
|||
|
|
{
|
|||
|
|
pair_state = PAIR_STATE_WAIT;
|
|||
|
|
last_radar_sec = 99;
|
|||
|
|
current_state = STATE_PAIR_WAIT;
|
|||
|
|
pair_timeout_ms = 0;
|
|||
|
|
captured_zone = 1;
|
|||
|
|
RF_SetMode(1);
|
|||
|
|
|
|||
|
|
// 初始化对码搜寻状态显示
|
|||
|
|
UI_ShowPairWaitPage(0);
|
|||
|
|
|
|||
|
|
// 快闪白色 RGB (双灯)
|
|||
|
|
RGB_Send(150, 150, 150, 150, 150, 150);
|
|||
|
|
|
|||
|
|
Uart_SendString("[PairApp] Started (WAIT)\r\n");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void PairApp_onRun(void)
|
|||
|
|
{
|
|||
|
|
u32 rx_addr;
|
|||
|
|
u8 rx_data;
|
|||
|
|
u8 flash;
|
|||
|
|
u8 frame;
|
|||
|
|
|
|||
|
|
if (pair_state == PAIR_STATE_WAIT) {
|
|||
|
|
// 白色 3Hz 快闪 (周期 333ms, 亮 166ms)
|
|||
|
|
flash = (ms_tick / 166) % 2;
|
|||
|
|
if (flash) RGB_Send(150, 150, 150, 150, 150, 150);
|
|||
|
|
else RGB_Send(0, 0, 0, 0, 0, 0);
|
|||
|
|
|
|||
|
|
frame = (u8)((ms_tick / 250) % 3);
|
|||
|
|
if (frame != last_radar_sec) {
|
|||
|
|
last_radar_sec = frame;
|
|||
|
|
UI_ShowPairWaitPage(frame);
|
|||
|
|
}
|
|||
|
|
if (pair_timeout_ms >= 30000UL) {
|
|||
|
|
pair_timeout_ms = 0;
|
|||
|
|
pair_state = PAIR_STATE_FAIL;
|
|||
|
|
current_state = STATE_PAIR_FAIL;
|
|||
|
|
fail_start_ms = ms_tick;
|
|||
|
|
UI_ShowPairFailPage(1);
|
|||
|
|
|
|||
|
|
// 红色常亮
|
|||
|
|
RGB_Send(200, 0, 0, 200, 0, 0);
|
|||
|
|
|
|||
|
|
Uart_SendString("[PairApp] Timeout\r\n");
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
if (EV1527_Decode(&rx_addr, &rx_data)) {
|
|||
|
|
// 排除 SOS 数据码 (0x08 代表 SOS 求救,不用于常规传感器配对)
|
|||
|
|
if (rx_data != 0x08)
|
|||
|
|
{
|
|||
|
|
captured_addr = rx_addr;
|
|||
|
|
pair_state = PAIR_STATE_CONFIRM;
|
|||
|
|
current_state = STATE_PAIR_CONFIRM;
|
|||
|
|
RF_SetMode(0);
|
|||
|
|
captured_zone = 1; // 初始为防区 1
|
|||
|
|
UI_ShowPairConfirmPage(captured_type, captured_zone);
|
|||
|
|
Uart_SendString("[PairApp] Sensor captured\r\n");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
} else if (pair_state == PAIR_STATE_CONFIRM) {
|
|||
|
|
// 橙色慢闪 (1.5Hz, 周期 666ms)
|
|||
|
|
u8 flash = (ms_tick / 333) % 2;
|
|||
|
|
if (flash) RGB_Send(100, 180, 0, 100, 180, 0); // 橙色
|
|||
|
|
else RGB_Send(0, 0, 0, 0, 0, 0);
|
|||
|
|
} else if (pair_state == PAIR_STATE_SUCCESS) {
|
|||
|
|
// 2 秒后自动返回二级菜单
|
|||
|
|
if (ms_tick - success_start_ms >= 2000 || ms_tick < success_start_ms)
|
|||
|
|
{
|
|||
|
|
AppManager_StartApp(APP_ID_MENU);
|
|||
|
|
}
|
|||
|
|
} else if (pair_state == PAIR_STATE_FAIL) {
|
|||
|
|
// 5 秒后自动返回二级菜单
|
|||
|
|
if (ms_tick - fail_start_ms >= 5000 || ms_tick < fail_start_ms)
|
|||
|
|
{
|
|||
|
|
AppManager_StartApp(APP_ID_MENU);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void PairApp_onClose(void)
|
|||
|
|
{
|
|||
|
|
RGB_Send(0, 0, 0, 0, 0, 0); // 关闭灯光
|
|||
|
|
MOTOR = 0;
|
|||
|
|
RF_SetMode(1);
|
|||
|
|
Uart_SendString("[PairApp] Closed\r\n");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
EventResult PairApp_onEvent(SystemEvent *evt)
|
|||
|
|
{
|
|||
|
|
if (pair_state == PAIR_STATE_CONFIRM) {
|
|||
|
|
if (evt->key_event == KEY_EVENT_UP_CLICK) {
|
|||
|
|
if (captured_zone < 99) {
|
|||
|
|
captured_zone++;
|
|||
|
|
UI_ShowPairConfirmPage(captured_type, captured_zone);
|
|||
|
|
}
|
|||
|
|
return EVENT_HANDLED;
|
|||
|
|
}
|
|||
|
|
if (evt->key_event == KEY_EVENT_DOWN_CLICK) {
|
|||
|
|
if (captured_zone > 1) {
|
|||
|
|
captured_zone--;
|
|||
|
|
UI_ShowPairConfirmPage(captured_type, captured_zone);
|
|||
|
|
}
|
|||
|
|
return EVENT_HANDLED;
|
|||
|
|
}
|
|||
|
|
if (evt->key_event == KEY_EVENT_CONFIRM_CLICK) {
|
|||
|
|
// 保存防区配对并显示成功反馈
|
|||
|
|
Add_Sensor_With_Zone(captured_addr, captured_type, captured_zone);
|
|||
|
|
pair_state = PAIR_STATE_SUCCESS;
|
|||
|
|
current_state = STATE_PAIR_SUCCESS;
|
|||
|
|
success_start_ms = ms_tick;
|
|||
|
|
UI_ShowPairSuccessPage();
|
|||
|
|
|
|||
|
|
// 绿色常亮且马达长振 400ms
|
|||
|
|
RGB_Send(0, 200, 0, 0, 200, 0);
|
|||
|
|
MOTOR = 1;
|
|||
|
|
Delay_ms(400);
|
|||
|
|
MOTOR = 0;
|
|||
|
|
return EVENT_HANDLED;
|
|||
|
|
}
|
|||
|
|
if (evt->key_event == KEY_EVENT_CONFIRM_LONG) {
|
|||
|
|
// 长按 Confirm 取消返回主菜单
|
|||
|
|
RGB_Send(0, 0, 0, 0, 0, 0);
|
|||
|
|
AppManager_StartApp(APP_ID_MENU);
|
|||
|
|
return EVENT_HANDLED;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 搜寻状态或确认状态下长按 DOWN 退出
|
|||
|
|
if (evt->key_event == KEY_EVENT_DOWN_LONG) {
|
|||
|
|
RGB_Send(0, 0, 0, 0, 0, 0);
|
|||
|
|
AppManager_StartApp(APP_ID_MENU);
|
|||
|
|
return EVENT_HANDLED;
|
|||
|
|
}
|
|||
|
|
return EVENT_IGNORED;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
/* =========================================================================
|
|||
|
|
* AlarmApp 回调实现
|
|||
|
|
* ========================================================================= */
|
|||
|
|
|
|||
|
|
void AlarmApp_OnStart(void)
|
|||
|
|
{
|
|||
|
|
u8 slot;
|
|||
|
|
u8 type = 0;
|
|||
|
|
u8 zone = 1;
|
|||
|
|
|
|||
|
|
current_state = STATE_ALARM;
|
|||
|
|
alarm_timer_ms = 0;
|
|||
|
|
alarm_flash_flag = 0;
|
|||
|
|
|
|||
|
|
if (Check_Sensor_ID(captured_addr, &slot)) {
|
|||
|
|
type = sensor_list[slot].type;
|
|||
|
|
zone = sensor_list[slot].zone;
|
|||
|
|
alarm_sensor_slot = slot;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 初始化显示警报界面
|
|||
|
|
UI_ShowAlarmPage(type, zone);
|
|||
|
|
|
|||
|
|
// 首次亮起防区对应颜色
|
|||
|
|
if (type == 0) RGB_Send(0, 180, 0, 0, 180, 0); // 门磁: 红色 (R=180)
|
|||
|
|
else if (type == 1) RGB_Send(100, 180, 0, 100, 180, 0); // PIR: 黄色
|
|||
|
|
else if (type == 2) RGB_Send(180, 0, 0, 180, 0, 0); // 烟感: 绿色 (G=180)
|
|||
|
|
else if (type == 3) RGB_Send(0, 180, 180, 0, 180, 180); // 气感: 紫色
|
|||
|
|
else RGB_Send(0, 0, 180, 0, 0, 180); // 水浸: 蓝色
|
|||
|
|
|
|||
|
|
Uart_SendString("[AlarmApp] Started\r\n");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void AlarmApp_onRun(void)
|
|||
|
|
{
|
|||
|
|
u8 type = sensor_list[alarm_sensor_slot].type;
|
|||
|
|
u8 flash = (ms_tick / 250) % 2; // 250ms 亮灭周期
|
|||
|
|
|
|||
|
|
// 同步控制 RGB 幻彩灯闪烁
|
|||
|
|
if (flash)
|
|||
|
|
{
|
|||
|
|
if (type == 0) RGB_Send(0, 180, 0, 0, 180, 0);
|
|||
|
|
else if (type == 1) RGB_Send(100, 180, 0, 100, 180, 0);
|
|||
|
|
else if (type == 2) RGB_Send(180, 0, 0, 180, 0, 0);
|
|||
|
|
else if (type == 3) RGB_Send(0, 180, 180, 0, 180, 180);
|
|||
|
|
else RGB_Send(0, 0, 180, 0, 0, 180);
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
RGB_Send(0, 0, 0, 0, 0, 0);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Truly AMOLED 粗红框闪烁
|
|||
|
|
if (alarm_flash_flag) {
|
|||
|
|
LCD_DrawRectBorder(4, 4, 112, 232, COLOR_RED);
|
|||
|
|
LCD_DrawRectBorder(6, 6, 108, 228, COLOR_RED);
|
|||
|
|
} else {
|
|||
|
|
LCD_DrawRectBorder(4, 4, 112, 232, COLOR_BLACK);
|
|||
|
|
LCD_DrawRectBorder(6, 6, 108, 228, COLOR_BLACK);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void AlarmApp_onClose(void)
|
|||
|
|
{
|
|||
|
|
RGB_Send(0, 0, 0, 0, 0, 0); // 关闭灯条
|
|||
|
|
MOTOR = 0;
|
|||
|
|
current_state = STATE_NORMAL;
|
|||
|
|
Uart_SendString("[AlarmApp] Closed\r\n");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
EventResult AlarmApp_onEvent(SystemEvent *evt)
|
|||
|
|
{
|
|||
|
|
// 任意键按下或长按 ➔ 清除报警返回时钟
|
|||
|
|
if (evt->key_event != KEY_EVENT_NONE) {
|
|||
|
|
AppManager_StartApp(APP_ID_CLOCK);
|
|||
|
|
return EVENT_HANDLED;
|
|||
|
|
}
|
|||
|
|
return EVENT_IGNORED;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
/* =========================================================================
|
|||
|
|
* SOSApp 回调实现
|
|||
|
|
* ========================================================================= */
|
|||
|
|
|
|||
|
|
static u8 sos_last_phase;
|
|||
|
|
|
|||
|
|
void SOSApp_OnStart(void)
|
|||
|
|
{
|
|||
|
|
current_state = STATE_SOS_EMITTED;
|
|||
|
|
sos_last_phase = 99;
|
|||
|
|
alarm_timer_ms = 0;
|
|||
|
|
UI_ShowSosPage();
|
|||
|
|
|
|||
|
|
// 立即启动双灯交替爆闪
|
|||
|
|
RGB_Send(0, 200, 0, 0, 0, 0);
|
|||
|
|
|
|||
|
|
Uart_SendString("[SOSApp] Started\r\n");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void SOSApp_onRun(void)
|
|||
|
|
{
|
|||
|
|
// 每 500ms 发射一次求救射频信号 (CLONED_ADDR 伴随 SOS 数据码 0x08)
|
|||
|
|
u8 sec_phase = (u8)((ms_tick / 500) % 2);
|
|||
|
|
if (sec_phase != sos_last_phase) {
|
|||
|
|
sos_last_phase = sec_phase;
|
|||
|
|
RF_SetMode(2);
|
|||
|
|
EV1527_Transmit(CLONED_ADDR, 0x08);
|
|||
|
|
RF_SetMode(0);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 50ms 周期控制双灯交替红色闪烁
|
|||
|
|
{
|
|||
|
|
u8 flash = (ms_tick / 50) % 2;
|
|||
|
|
if (flash) {
|
|||
|
|
RGB_Send(0, 200, 0, 0, 0, 0); // 灯1亮红,灯2灭
|
|||
|
|
} else {
|
|||
|
|
RGB_Send(0, 0, 0, 0, 200, 0); // 灯1灭,灯2亮红
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Truly AMOLED 边框闪烁 (红粗边框 + 白细边框)
|
|||
|
|
if (alarm_flash_flag) {
|
|||
|
|
LCD_DrawRectBorder(4, 4, 112, 232, COLOR_RED);
|
|||
|
|
LCD_DrawRectBorder(5, 5, 110, 230, COLOR_RED);
|
|||
|
|
LCD_DrawRectBorder(8, 8, 104, 224, COLOR_WHITE);
|
|||
|
|
} else {
|
|||
|
|
LCD_DrawRectBorder(4, 4, 112, 232, COLOR_BLACK);
|
|||
|
|
LCD_DrawRectBorder(5, 5, 110, 230, COLOR_BLACK);
|
|||
|
|
LCD_DrawRectBorder(8, 8, 104, 224, COLOR_BLACK);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void SOSApp_onClose(void)
|
|||
|
|
{
|
|||
|
|
RGB_Send(0, 0, 0, 0, 0, 0); // 关闭灯条
|
|||
|
|
MOTOR = 0;
|
|||
|
|
current_state = STATE_NORMAL;
|
|||
|
|
Uart_SendString("[SOSApp] Closed\r\n");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
EventResult SOSApp_onEvent(SystemEvent *evt)
|
|||
|
|
{
|
|||
|
|
// 短按或长按任意键 ➔ 退出求救状态返回待机时钟
|
|||
|
|
if (evt->key_event != KEY_EVENT_NONE) {
|
|||
|
|
AppManager_StartApp(APP_ID_CLOCK);
|
|||
|
|
return EVENT_HANDLED;
|
|||
|
|
}
|
|||
|
|
return EVENT_IGNORED;
|
|||
|
|
}
|