pebble/tests/fakes/fake_app_timer.h
2025-01-27 11:38:16 -08:00

162 lines
4.5 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.
*/
#pragma once
#include "applib/app_timer.h"
#include "system/logging.h"
#include <string.h>
typedef struct FakeAppTimer {
uint32_t timeout_ms;
bool repeating;
AppTimerCallback callback;
void* callback_data;
struct FakeAppTimer *next;
uint32_t timer_id;
} FakeAppTimer;
static FakeAppTimer *s_fake_app_timer_head;
static uint32_t s_fake_app_timer_next_id;
static FakeAppTimer *prv_find_fake_app_timer_by_timer_id(uint32_t timer_id) {
for (FakeAppTimer *node = s_fake_app_timer_head; node != NULL; node = node->next) {
if (node->timer_id == timer_id) {
return node;
}
}
return NULL;
}
void fake_app_timer_init(void) {
s_fake_app_timer_head = NULL;
s_fake_app_timer_next_id = 0;
}
void fake_app_timer_deinit(void) {
FakeAppTimer *timer = s_fake_app_timer_head;
while (timer) {
FakeAppTimer *next = timer->next;
app_timer_cancel((AppTimer *)timer);
timer = next;
}
}
uint32_t fake_app_timer_get_timeout(AppTimer *timer) {
FakeAppTimer *fake_timer = prv_find_fake_app_timer_by_timer_id((uintptr_t)timer);
if (fake_timer) {
return fake_timer->timeout_ms;
}
return 0;
}
bool fake_app_timer_is_scheduled(AppTimer *timer) {
return (prv_find_fake_app_timer_by_timer_id((uintptr_t)timer) != NULL);
}
AppTimer* app_timer_register(uint32_t timeout_ms, AppTimerCallback callback, void* callback_data) {
FakeAppTimer *fake_timer = malloc(sizeof(FakeAppTimer));
*fake_timer = (FakeAppTimer) {
.timeout_ms = timeout_ms,
.callback = callback,
.callback_data = callback_data,
.next = s_fake_app_timer_head,
.timer_id = ++s_fake_app_timer_next_id,
};
s_fake_app_timer_head = fake_timer;
return (AppTimer *)(uintptr_t)fake_timer->timer_id;
}
AppTimer* app_timer_register_repeatable(uint32_t timeout_ms,
AppTimerCallback callback,
void* callback_data,
bool repeating) {
FakeAppTimer *fake_timer = malloc(sizeof(FakeAppTimer));
*fake_timer = (FakeAppTimer) {
.timeout_ms = timeout_ms,
.repeating = repeating,
.callback = callback,
.callback_data = callback_data,
.next = s_fake_app_timer_head,
.timer_id = ++s_fake_app_timer_next_id,
};
s_fake_app_timer_head = fake_timer;
return (AppTimer *)(uintptr_t)fake_timer->timer_id;
}
bool app_timer_reschedule(AppTimer *timer, uint32_t new_timeout_ms) {
FakeAppTimer *fake_timer = prv_find_fake_app_timer_by_timer_id((uintptr_t)timer);
if (fake_timer) {
fake_timer->timeout_ms = new_timeout_ms;
return true;
}
return false;
}
static void prv_unlink_and_free_timer(FakeAppTimer *timer) {
FakeAppTimer *prev_timer = s_fake_app_timer_head;
if (timer == s_fake_app_timer_head) {
// The timer is the head
s_fake_app_timer_head = timer->next;
} else {
// Not the head, find the previous one:
while (prev_timer && prev_timer != timer &&
prev_timer->next && prev_timer->next != timer) {
prev_timer = prev_timer->next;
}
if (!prev_timer) {
PBL_LOG(LOG_LEVEL_ERROR, "Tried to unlink and free non-existing timer %p", timer);
return;
}
prev_timer->next = timer->next;
}
free(timer);
}
void app_timer_cancel(AppTimer *timer) {
FakeAppTimer *fake_timer = prv_find_fake_app_timer_by_timer_id((uintptr_t)timer);
if (fake_timer) {
prv_unlink_and_free_timer(fake_timer);
}
}
bool app_timer_trigger(AppTimer *timer) {
FakeAppTimer *fake_timer = prv_find_fake_app_timer_by_timer_id((uintptr_t)timer);
if (fake_timer) {
AppTimerCallback callback = fake_timer->callback;
void *data = fake_timer->callback_data;
if (!fake_timer->repeating) {
prv_unlink_and_free_timer(fake_timer);
}
callback(data);
return true;
}
return false;
}
void *app_timer_get_data(AppTimer *timer) {
FakeAppTimer *fake_timer = prv_find_fake_app_timer_by_timer_id((uintptr_t)timer);
if (fake_timer) {
return fake_timer->callback_data;
} else {
return NULL;
}
}