Files
stc32g128k/App/event.c

271 lines
8.9 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "event.h"
#include "app_manager.h"
#include "database.h"
#include "system.h"
#include "clock.h"
#include "xtell.h"
// 定义事件环形队列的最大深度为 8
#define EVENT_QUEUE_DEPTH 8
// 环形队列存储数组 (存放在单片机 idata 快速RAM区中)
static SystemEvent idata event_queue[EVENT_QUEUE_DEPTH];
static u8 queue_head = 0; // 队首读指针
static u8 queue_tail = 0; // 队尾写指针
static u8 queue_count = 0; // 当前队列内有效事件总数
/**
* @brief 初始化/清空事件队列
*/
void EventQueue_Init(void)
{
queue_head = 0;
queue_tail = 0;
queue_count = 0;
}
/**
* @brief 将普通事件压入队尾
* @param evt 输入的系统事件
* @return bit 1-成功0-失败
*/
bit EventQueue_Push(SystemEvent evt)
{
if (queue_count >= EVENT_QUEUE_DEPTH) return 0; // 队列满,丢弃事件
EA = 0; // 关闭全局中断,保护临界区操作的原子性
event_queue[queue_tail] = evt; // 存入队尾
queue_tail = (queue_tail + 1) % EVENT_QUEUE_DEPTH; // 尾指针向后移动,回环
queue_count++; // 有效计数加 1
EA = 1; // 恢复全局中断
return 1;
}
/**
* @brief 将高优先级/紧急事件强行插到队首
* @param evt 输入的系统事件
* @return bit 1-成功0-失败
*/
bit EventQueue_InsertFront(SystemEvent evt)
{
if (queue_count >= EVENT_QUEUE_DEPTH) return 0; // 队列满,插队失败
EA = 0; // 屏蔽中断
// 头指针向前移动一位(带回环防溢出)
queue_head = (queue_head - 1 + EVENT_QUEUE_DEPTH) % EVENT_QUEUE_DEPTH;
event_queue[queue_head] = evt; // 存入腾出的队首位置
queue_count++; // 计数加 1
EA = 1; // 恢复中断
return 1;
}
/**
* @brief 从队首弹出一个缓冲事件
* @return SystemEvent 返回弹出的事件。若空返回空闲事件
*/
SystemEvent EventQueue_Pop(void)
{
SystemEvent evt;
// 默认空事件属性
evt.key_event = KEY_EVENT_NONE;
evt.extra_data = 0;
evt.extra_size = 0;
if (queue_count == 0) return evt; // 队空,直接返回空闲事件
EA = 0; // 屏蔽中断
evt = event_queue[queue_head]; // 读取队首数据
queue_head = (queue_head + 1) % EVENT_QUEUE_DEPTH; // 头指针向后移动,回环
queue_count--; // 有效计数减 1
EA = 1; // 恢复中断
return evt;
}
/**
* @brief 判断队列是否为空
*/
bit EventQueue_IsEmpty(void)
{
return (queue_count == 0) ? 1 : 0;
}
/**
* @brief 判断队列是否已满
*/
bit EventQueue_IsFull(void)
{
return (queue_count >= EVENT_QUEUE_DEPTH) ? 1 : 0;
}
/**
* @brief 获取当前队列中的事件总数
*/
u8 EventQueue_GetCount(void)
{
return queue_count;
}
/**
* @brief 事件分发器核心轮询逻辑
* @details 逐一处理队列中的事件,并根据系统当前的运行模式进行拦截、跳转或下发派发。
*/
void Event_Dispatcher_Loop(void)
{
SystemEvent evt = EventQueue_Pop(); // 弹出一个事件
// 如果是无事发生的空事件,直接退出
if (evt.key_event == KEY_EVENT_NONE && evt.extra_size == 0) {
return;
}
inactivity_timer = 0; // 捕获到有效事件,清零休眠计时器,重置闲置超时
// 串口打印调试信息
XTELL_LOG("[EVENT] key=");
XTELL_LOG_HEX8((u8)evt.key_event);
XTELL_LOG("\r\n");
// SOS 按键紧急处理:若当前前台不为 SOS 应用,接收到 SOS 键动作,立即强行切入到 SOS_APP 并执行求救
if ((evt.key_event == KEY_EVENT_SOS_CLICK || evt.key_event == KEY_EVENT_SOS_LONG) &&
AppManager_GetActiveAppID() != APP_ID_SOS) {
AppManager_StartApp(APP_ID_SOS);
return;
}
// 常规事件(如普通的按键点击)直接透传分发给当前处于前台活跃的应用
AppManager_DispatchEvent(evt);
}
/**
* @brief 定时器 1 初始化,设定 1ms 中断周期
*/
void Timer1_Init(void)
{
AUXR |= 0x40; // 设定定时器 1 为 1T 模式 (无分频,主频直接输入)
TMOD &= 0x0F; // 设置定时器 1 模式寄存器,保留低四位 (定时器0配置)
{
// 按照系统主频 (MAIN_Fosc) 计算 1ms 对应的重装载值
u16 reload = (u16)(65536UL - (MAIN_Fosc / 1000UL));
TL1 = (u8)reload; // 载入低 8 位
TH1 = (u8)(reload >> 8);// 载入高 8 位
}
ET1 = 1; // 开启定时器 1 中断允许
TR1 = 1; // 启动定时器 1 计数
EA = 1; // 开启全局中断允许
}
/**
* @brief 定时器 1 中断服务程序 (每 1ms 触发一次)
* @details 承担了系统软时钟计算、10ms 周期性按键消抖扫描的功能。马达等特定业务已剥离至 App 内部。
*/
void Timer1_Isr(void) interrupt 3
{
SystemEvent evt;
// 1ms 定时更新软时钟
Clock_IncMS();
// 报警屏幕红边框以 100ms 周期亮灭,进行颜色爆闪指示
alarm_flash_flag = (ms_tick / 100) % 2;
/* 物理按键扫描及消抖状态机逻辑 (每 10ms 轮询一次) */
key_scan_timer++;
if (key_scan_timer >= 10) {
// 读取按键的电平信号 (由于有上拉电阻,未按下为高 1按下为低 0所以取反做正逻辑)
u8 raw_up = !KEY_UP;
u8 raw_down = !KEY_DOWN;
u8 raw_confirm = !KEY_CONFIRM;
u8 raw_sos = 0; // 临时注释关闭 SOS 物理按键电平检测,防浮空干扰
key_scan_timer = 0; // 重置扫描分频计数器
// 检测到有任意按键处于下压状态,立即将无操作闲置休眠计时器归零
if (raw_up || raw_down || raw_confirm || raw_sos) {
inactivity_timer = 0;
} else {
// 如果在常态下(非休眠、非报警、非紧急求救),累加闲置时间
if (current_state != STATE_SLEEP && current_state != STATE_ALARM && current_state != STATE_SOS_EMITTED) {
inactivity_timer++;
}
}
// 默认将派发事件重置为空
evt.key_event = KEY_EVENT_NONE;
evt.extra_data = 0;
evt.extra_size = 0;
// 双键组合判定:▲ 键 and ▼ 键同时按下的消抖与生成
if (raw_up && raw_down) {
comb_hold++;
if (comb_hold == 300) { // 持续按下达 3 秒 (300 * 10ms = 3s)
evt.key_event = KEY_EVENT_UP_DOWN_COMB;
EventQueue_Push(evt); // 压入队列
}
key_up_hold = 0; // 清零单个按键计数,防止双击事件干扰
key_down_hold = 0;
} else {
comb_hold = 0; // 组合键松开归零
// ▲ (KEY_UP) 按键状态机
if (raw_up) {
key_up_hold++;
if (key_up_hold == 300) { // 达到 3 秒判定为长按
evt.key_event = KEY_EVENT_UP_LONG;
EventQueue_Push(evt);
}
} else {
// 如果松开时按下计数在消抖阈值20ms至长按阈值3s之间则判定为一次短按
if (key_up_hold >= 2 && key_up_hold < 300) {
evt.key_event = KEY_EVENT_UP_CLICK;
EventQueue_Push(evt);
}
key_up_hold = 0; // 释放归零
}
// ▼ (KEY_DOWN) 按键状态机
if (raw_down) {
key_down_hold++;
if (key_down_hold == 300) { // 长按 3 秒
evt.key_event = KEY_EVENT_DOWN_LONG;
EventQueue_Push(evt);
}
} else {
if (key_down_hold >= 2 && key_down_hold < 300) {
evt.key_event = KEY_EVENT_DOWN_CLICK;
EventQueue_Push(evt);
}
key_down_hold = 0; // 释放归零
}
// ■ (KEY_CONFIRM) 确认按键状态机
if (raw_confirm) {
key_confirm_hold++;
if (key_confirm_hold == 300) { // 长按 3 秒打开主菜单
evt.key_event = KEY_EVENT_CONFIRM_LONG;
EventQueue_Push(evt);
}
} else {
if (key_confirm_hold >= 2 && key_confirm_hold < 300) {
evt.key_event = KEY_EVENT_CONFIRM_CLICK;
EventQueue_Push(evt);
}
key_confirm_hold = 0; // 释放归零
}
/*
// SOS 物理求救按键状态机
if (raw_sos) {
key_sos_hold++;
if (key_sos_hold == 300) { // 长按 3 秒,发出求救,插入队首
evt.key_event = KEY_EVENT_SOS_LONG;
EventQueue_InsertFront(evt);
}
} else {
if (key_sos_hold >= 2 && key_sos_hold < 300) { // 短按即呼救,插入队首
evt.key_event = KEY_EVENT_SOS_CLICK;
EventQueue_InsertFront(evt);
}
key_sos_hold = 0; // 释放归零
}
*/
}
}
}