pebble/src/fw/services/common/animation_service.c
2025-01-27 11:38:16 -08:00

146 lines
4.2 KiB
C

/*
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "applib/ui/animation_private.h"
#include "applib/app_logging.h"
#include "kernel/events.h"
#include "kernel/kernel_applib_state.h"
#include "process_management/process_manager.h"
#include "process_state/app_state/app_state.h"
#include "services/common/new_timer/new_timer.h"
#include "system/passert.h"
#include "syscall/syscall.h"
#include "syscall/syscall_internal.h"
// The timer ID used for each task that we support
static TimerID s_kernel_main_timer_id = TIMER_INVALID_ID;
static TimerID s_app_timer_id = TIMER_INVALID_ID;
static bool s_kernel_main_event_pending;
static bool s_app_event_pending;
// ------------------------------------------------------------------------------------------
void animation_service_cleanup(PebbleTask task) {
PBL_ASSERT_TASK(PebbleTask_KernelMain);
if (task == PebbleTask_KernelMain) {
if (s_kernel_main_timer_id != TIMER_INVALID_ID) {
new_timer_delete(s_kernel_main_timer_id);
s_kernel_main_timer_id = TIMER_INVALID_ID;
}
s_kernel_main_event_pending = false;
} else if (task == PebbleTask_App) {
if (s_app_timer_id != TIMER_INVALID_ID) {
new_timer_delete(s_app_timer_id);
s_app_timer_id = TIMER_INVALID_ID;
}
s_app_event_pending = false;
}
}
// ------------------------------------------------------------------------------------------
static void prv_timer_callback(void * context) {
PebbleTask task = (PebbleTask)context;
PebbleEvent e = {
.type = PEBBLE_CALLBACK_EVENT,
.callback = {
.callback = animation_private_timer_callback
}
};
switch (task) {
case PebbleTask_KernelMain:
if (!s_kernel_main_event_pending) {
s_kernel_main_event_pending = true;
e.callback.data = (void *)kernel_applib_get_animation_state();
event_put(&e);
}
break;
case PebbleTask_App:
if (!s_app_event_pending) {
e.callback.data = (void *)app_state_get_animation_state();
s_app_event_pending = process_manager_send_event_to_process(task, &e);
}
break;
default:
PBL_CROAK("Invalid task %s", pebble_task_get_name(pebble_task_get_current()));
}
}
// ------------------------------------------------------------------------------------------
DEFINE_SYSCALL(void, animation_service_timer_event_received, void) {
PebbleTask task = pebble_task_get_current();
if (task == PebbleTask_KernelMain) {
s_kernel_main_event_pending = false;
} else if (task == PebbleTask_App) {
s_app_event_pending = false;
} else {
if (PRIVILEGE_WAS_ELEVATED) {
syscall_failed();
}
return;
}
}
// ------------------------------------------------------------------------------------------
DEFINE_SYSCALL(void, animation_service_timer_schedule, uint32_t ms) {
PebbleTask task = pebble_task_get_current();
TimerID *timer_id;
if (task == PebbleTask_KernelMain) {
timer_id = &s_kernel_main_timer_id;
} else if (task == PebbleTask_App) {
timer_id = &s_app_timer_id;
} else {
if (PRIVILEGE_WAS_ELEVATED) {
syscall_failed();
}
return;
}
// Need to create the timer?
bool success = false;
if (*timer_id == TIMER_INVALID_ID) {
*timer_id = new_timer_create();
}
// Schedule/reschedule it
if (*timer_id != TIMER_INVALID_ID) {
success = new_timer_start(*timer_id, ms, prv_timer_callback, (void *)(uintptr_t)task,
0 /*flags */);
}
if (!success) {
APP_LOG(APP_LOG_LEVEL_ERROR, "Error scheduling timer");
}
}
// ---------------------------------------------------------------------------
// Used for unit tests only
TimerID animation_service_test_get_timer_id(void) {
return s_kernel_main_timer_id;
}