Files
arcs/apps-ui/apps/llm/models/model_alarm.c
2026-08-13 16:50:52 +08:00

333 lines
8.5 KiB
C

/**
* @file model_alarm.c
* @brief Alarm data model implementation
*/
#include "model_alarm.h"
#include <string.h>
#include <stdio.h>
#include <stdbool.h>
#include <time.h>
#include <sys/time.h>
#include "lisa_ui.h"
#include "lisa_ui_invoke.h"
#include "lisa_ui_nav_scr_ids.h"
#ifdef LISA_UI_PLATFORM_ARCS
#include "voice_msg.h"
#include "service_alarm.h"
#include "app_datas.h"
#define ALARM_TRIGGER_NAV_DELAY_MS 200
#endif
#define TAG "model_alarm"
/**
* @brief Alarm model context
*/
typedef struct {
alarm_data_t data;
char event_text[128];
bool initialized;
bool is_ringing; /* 闹钟是否正在响铃 */
uint32_t alarm_count;
} alarm_model_ctx_t;
static alarm_model_ctx_t g_alarm_ctx = {0};
#ifdef LISA_UI_PLATFORM_ARCS
static void alarm_trigger_nav_ui_worker(void *arg, uint32_t len)
{
if (!arg || len < sizeof(struct service_alarm)) {
LISA_UI_LOGE("Model: invalid alarm trigger payload");
return;
}
const struct service_alarm *alarm = (const struct service_alarm *)arg;
LISA_UI_LOGI("Model: Alarm triggered - timestamp: %llu", alarm->timestamp);
g_alarm_ctx.data.timestamp = alarm->timestamp;
g_alarm_ctx.event_text[0] = '\0';
g_alarm_ctx.initialized = true;
g_alarm_ctx.is_ringing = true;
int top_id = lisa_ui_nav_scr_get_top_id();
if (top_id == LISA_UI_NAV_SCR_ID_ALARM_RING) {
LISA_UI_LOGI("Already on alarm ring page, skipping navigation");
return;
}
if (top_id != LISA_UI_NAV_SCR_ID_HOME) {
LISA_UI_LOGI("Model: Navigating to home before alarm ring, top_id=%d", top_id);
lisa_ui_nav_scr_nav_to(LISA_UI_NAV_SCR_ID_HOME);
}
LISA_UI_LOGI("Model: Navigating to alarm ring page");
lisa_ui_nav_scr_nav_to(LISA_UI_NAV_SCR_ID_ALARM_RING);
}
static void on_alarm_create_event(void *unused, uint32_t msg_id, void *data, uint32_t len, void *user_data)
{
(void)unused;
(void)msg_id;
(void)user_data;
struct service_alarm *alarm = (struct service_alarm *)data;
LISA_UI_LOGI("Model: Alarm created - timestamp: %llu", alarm->timestamp);
g_alarm_ctx.alarm_count++;
LISA_UI_INVOKE_UI_ARG_PTR(alarm, sizeof(struct service_alarm), {
g_alarm_ctx.data.timestamp = _invoke_alarm->timestamp;
g_alarm_ctx.event_text[0] = '\0';
g_alarm_ctx.initialized = true;
if (lisa_ui_nav_scr_get_top_id() == LISA_UI_NAV_SCR_ID_ALARM_SUCCESS) {
LISA_UI_LOGI("Already on alarm success page, skipping navigation");
return;
}
lisa_ui_nav_scr_nav_to(LISA_UI_NAV_SCR_ID_ALARM_SUCCESS);
});
}
static void on_alarm_delete_event(void *unused, uint32_t msg_id, void *data, uint32_t len, void *user_data)
{
(void)unused;
(void)msg_id;
(void)data;
(void)len;
(void)user_data;
if (g_alarm_ctx.alarm_count > 0) {
g_alarm_ctx.alarm_count--;
}
}
static void on_alarm_query_event(void *unused, uint32_t msg_id, void *data, uint32_t len, void *user_data)
{
(void)unused;
(void)msg_id;
(void)user_data;
if (!data || len < sizeof(uint32_t)) {
return;
}
g_alarm_ctx.alarm_count = *(uint32_t *)data;
}
static void on_alarm_trigger_event(void *unused, uint32_t msg_id, void *data, uint32_t len, void *user_data)
{
(void)unused;
(void)msg_id;
(void)user_data;
struct service_alarm *alarm = (struct service_alarm *)data;
if (!alarm) {
LISA_UI_LOGE("Model: alarm trigger data is NULL");
return;
}
#ifdef LISA_UI_PLATFORM_ARCS
struct app_datas *app_datas = get_app_datas();
if (app_datas) {
LISA_UI_LOGI("Model: Before setting - can_wakeup=%d, voice_work_mode=%d",
app_datas->can_wakeup, app_datas->voice_work_mode);
app_datas->can_wakeup = true;
app_datas->voice_work_mode |= VOICE_WORK_MODE_VOICE_WAKEUP;
LISA_UI_LOGI("Model: After setting - can_wakeup=%d, voice_work_mode=%d",
app_datas->can_wakeup, app_datas->voice_work_mode);
} else {
LISA_UI_LOGE("Model: Failed to get app_datas!");
}
/* Alarm page switch can race with MCP session UI transition; stop MCP first. */
voice_msg_pub(VOICE_MSG_CLOUD_MCP_CHAT_EXIT, NULL, 0);
if (lisa_ui_invoke_ui_delayed(alarm_trigger_nav_ui_worker, alarm, sizeof(struct service_alarm),
ALARM_TRIGGER_NAV_DELAY_MS) != 0) {
LISA_UI_LOGE("Model: failed to schedule alarm ring navigation");
}
#endif
}
#endif
int model_alarm_init(void)
{
if (g_alarm_ctx.initialized) {
return 0;
}
LISA_UI_LOGI("Initializing alarm model");
#ifdef LISA_UI_PLATFORM_ARCS
voice_msg_sub(VOICE_MSG_ALARM_CREATE, on_alarm_create_event, NULL);
voice_msg_sub(VOICE_MSG_ALARM_DELETE, on_alarm_delete_event, NULL);
voice_msg_sub(VOICE_MSG_ALARM_QUERY, on_alarm_query_event, NULL);
voice_msg_sub(VOICE_MSG_ALARM_TRIGGER, on_alarm_trigger_event, NULL);
uint32_t cnt = 0;
struct service_alarm *service_alarms = service_alarm_get_all(&cnt);
if (service_alarms) {
lisa_mem_free(service_alarms);
}
g_alarm_ctx.alarm_count = cnt;
#endif
g_alarm_ctx.initialized = true;
LISA_UI_LOGI("Alarm model initialized");
return 0;
}
void model_alarm_set_data(const alarm_data_t *data)
{
if (!data) {
LISA_UI_LOGE("Invalid alarm data");
return;
}
g_alarm_ctx.data = *data;
LISA_UI_LOGI("Alarm data set - timestamp: %llu", (unsigned long long)data->timestamp);
}
int model_alarm_get_data(alarm_data_t *data)
{
if (!data) {
LISA_UI_LOGE("Invalid output parameter");
return -1;
}
if (!g_alarm_ctx.initialized) {
LISA_UI_LOGW("Alarm model not initialized");
return -1;
}
*data = g_alarm_ctx.data;
return 0;
}
const char *model_alarm_get_event_text(void)
{
return g_alarm_ctx.event_text;
}
int model_alarm_get_time_info(uint64_t timestamp, alarm_time_info_t *info)
{
if (!info) {
LISA_UI_LOGE("Invalid parameter");
return -1;
}
struct timeval tv;
time_t current_time = time(NULL);
if (gettimeofday(&tv, NULL) == 0) {
current_time = tv.tv_sec;
}
time_t alarm_time = (time_t)timestamp;
struct tm alarm_tm_struct;
struct tm *alarm_tm = localtime_r(&alarm_time, &alarm_tm_struct);
if (!alarm_tm) {
LISA_UI_LOGE("Failed to convert timestamp");
return -1;
}
info->year = alarm_tm->tm_year + 1970;
info->month = alarm_tm->tm_mon + 1;
info->day = alarm_tm->tm_mday;
info->hour = alarm_tm->tm_hour;
info->minute = alarm_tm->tm_min;
int64_t local_ts = (int64_t)timestamp + (int64_t)8 * 3600;
int64_t days_since_epoch = local_ts / 86400;
info->weekday = (int)((4 + (days_since_epoch % 7) + 7) % 7);
int64_t alarm_local_days = ((int64_t)timestamp + (int64_t)8 * 3600) / 86400;
int64_t current_local_days = ((int64_t)current_time + (int64_t)8 * 3600) / 86400;
int64_t day_diff = alarm_local_days - current_local_days;
info->is_today = (day_diff == 0);
info->is_tomorrow = (day_diff == 1);
return 0;
}
int model_alarm_delete_by_timestamp(uint64_t timestamp)
{
#ifdef LISA_UI_PLATFORM_ARCS
int r = ls_alarm_delete_by_timestamp(timestamp);
return r;
#endif
return 0;
}
void model_alarm_free(void *alarms)
{
if (alarms) {
lisa_ui_free(alarms);
}
}
uint32_t model_alarm_count_get(void)
{
return g_alarm_ctx.alarm_count;
}
alarm_data_t *model_alarm_get_all(uint32_t *cnt)
{
if (!cnt) {
LISA_UI_LOGE("Invalid parameter: cnt is NULL");
return NULL;
}
#ifdef LISA_UI_PLATFORM_ARCS
if (!service_alarm_init_done()) {
*cnt = 0;
return NULL;
}
uint32_t alarm_count = 0;
struct service_alarm *service_alarms = service_alarm_get_all(&alarm_count);
*cnt = alarm_count;
if (alarm_count == 0 || service_alarms == NULL) {
return NULL;
}
// Allocate memory for alarm_data_t array
alarm_data_t *alarms = lisa_ui_malloc(sizeof(alarm_data_t) * alarm_count);
if (alarms == NULL) {
LISA_UI_LOGE("Failed to allocate memory for alarms");
lisa_mem_free(service_alarms);
*cnt = 0;
return NULL;
}
// Convert service_alarm to alarm_data_t
for (uint32_t i = 0; i < alarm_count; i++) {
alarms[i].timestamp = service_alarms[i].timestamp;
LISA_UI_LOGI("alarm %d, timestamp:%llu", i, alarms[i].timestamp);
}
// Free the service_alarm array
lisa_mem_free(service_alarms);
LISA_UI_LOGI("Got %u alarms", alarm_count);
return alarms;
#else
*cnt = 0;
return NULL;
#endif
}