mirror of
https://github.com/DarkFlippers/unleashed-firmware.git
synced 2025-12-12 04:34:43 +04:00
[FL-3846] Event Loop Timers (#3721)
* Implement POC event loop tmers (not all edge cases are handled) * Use a separate ready list to allow for (re)starting and stopping of timers from callback * Improve the test application * Improve timer API and test application * Improve timeout calculation logic * Improve timer API, update documentation * Fix API usage error * Update doxygen comments * Revert the old (correct) check * Improve function naming * Check whether a timer was on the expired list before processing it * Implement tick callback * Add critical sections to improve timer consistency * Simplify event loop timer API * Remove redundant search * Refactor timer logic, use message queue * Simplify FuriEventLoopTimer API * Improve event loop timer logic * Update the f18 target * Remove superfluous clears * Correct f18 api symbols * Fix doxygen comments * Update .pvsconfig * Use a double push list instead of deque * Update .pvsconfig * Add pending callback functionality * Restore unprocessed flags when applicable * Refactor Dolphin app to use FuriEventLoop * Improve naming * Update naming some more * Fix a typo Co-authored-by: Silent <CookiePLMonster@users.noreply.github.com> * Fix wait time in example * Bump API version * Debug: multiple of 25 timings in event loop blink test * Separate FuriEventLoopTimer to its own set of files * Improve start time calculation for periodic timers * Do not use dynamic allocations for timer requests * Split the tick functionality in separate files, rearrange code * Improve timer queue handling * Properly reset GPIO pins in the test app * Properly initialise GPIO pins in the test app too * Furi: variable naming in event loop * Furi: fix spelling in event loop Co-authored-by: あく <alleteam@gmail.com> Co-authored-by: Silent <CookiePLMonster@users.noreply.github.com>
This commit is contained in:
10
applications/debug/event_loop_blink_test/application.fam
Normal file
10
applications/debug/event_loop_blink_test/application.fam
Normal file
@@ -0,0 +1,10 @@
|
||||
App(
|
||||
appid="event_loop_blink_test",
|
||||
name="Event Loop Blink Test",
|
||||
apptype=FlipperAppType.DEBUG,
|
||||
entry_point="event_loop_blink_test_app",
|
||||
requires=["input"],
|
||||
stack_size=1 * 1024,
|
||||
order=20,
|
||||
fap_category="Debug",
|
||||
)
|
||||
169
applications/debug/event_loop_blink_test/event_loop_blink_test.c
Normal file
169
applications/debug/event_loop_blink_test/event_loop_blink_test.c
Normal file
@@ -0,0 +1,169 @@
|
||||
#include <furi.h>
|
||||
#include <furi_hal_resources.h>
|
||||
|
||||
#include <gui/gui.h>
|
||||
#include <gui/elements.h>
|
||||
#include <gui/view_port.h>
|
||||
|
||||
#include <input/input.h>
|
||||
|
||||
#define TAG "EventLoopBlinkTest"
|
||||
|
||||
#define TIMER_COUNT (6U)
|
||||
|
||||
typedef struct {
|
||||
FuriEventLoop* event_loop;
|
||||
FuriMessageQueue* input_queue;
|
||||
FuriEventLoopTimer* timers[TIMER_COUNT];
|
||||
} EventLoopBlinkTestApp;
|
||||
|
||||
static const GpioPin* blink_gpio_pins[] = {
|
||||
&gpio_ext_pa7,
|
||||
&gpio_ext_pa6,
|
||||
&gpio_ext_pa4,
|
||||
&gpio_ext_pb3,
|
||||
&gpio_ext_pb2,
|
||||
&gpio_ext_pc3,
|
||||
};
|
||||
|
||||
static_assert(COUNT_OF(blink_gpio_pins) == TIMER_COUNT);
|
||||
|
||||
static const uint32_t timer_intervals[] = {
|
||||
25,
|
||||
50,
|
||||
100,
|
||||
200,
|
||||
400,
|
||||
800,
|
||||
};
|
||||
|
||||
static_assert(COUNT_OF(timer_intervals) == TIMER_COUNT);
|
||||
|
||||
static void blink_gpio_init(void) {
|
||||
for(size_t i = 0; i < TIMER_COUNT; ++i) {
|
||||
furi_hal_gpio_init_simple(blink_gpio_pins[i], GpioModeOutputPushPull);
|
||||
furi_hal_gpio_write(blink_gpio_pins[i], false);
|
||||
}
|
||||
|
||||
furi_hal_gpio_init_simple(&gpio_ext_pc0, GpioModeOutputPushPull);
|
||||
furi_hal_gpio_write(&gpio_ext_pc0, false);
|
||||
}
|
||||
|
||||
static void blink_gpio_deinit(void) {
|
||||
for(size_t i = 0; i < TIMER_COUNT; ++i) {
|
||||
furi_hal_gpio_write(blink_gpio_pins[i], false);
|
||||
furi_hal_gpio_init_simple(blink_gpio_pins[i], GpioModeAnalog);
|
||||
}
|
||||
|
||||
furi_hal_gpio_write(&gpio_ext_pc0, false);
|
||||
furi_hal_gpio_init_simple(&gpio_ext_pc0, GpioModeAnalog);
|
||||
}
|
||||
|
||||
static void view_port_draw_callback(Canvas* canvas, void* context) {
|
||||
UNUSED(context);
|
||||
canvas_clear(canvas);
|
||||
elements_text_box(
|
||||
canvas,
|
||||
0,
|
||||
0,
|
||||
canvas_width(canvas),
|
||||
canvas_height(canvas),
|
||||
AlignCenter,
|
||||
AlignCenter,
|
||||
"\e#Event Loop Timers Test\e#\n"
|
||||
"Press buttons\n"
|
||||
"to enable or disable timers\n"
|
||||
"\e#Exit\e# = long press \e#Back\e#",
|
||||
false);
|
||||
}
|
||||
|
||||
static void view_port_input_callback(InputEvent* input_event, void* context) {
|
||||
EventLoopBlinkTestApp* app = context;
|
||||
furi_message_queue_put(app->input_queue, input_event, 0);
|
||||
}
|
||||
|
||||
static bool input_queue_callback(FuriMessageQueue* queue, void* context) {
|
||||
EventLoopBlinkTestApp* app = context;
|
||||
|
||||
InputEvent event;
|
||||
FuriStatus status = furi_message_queue_get(queue, &event, 0);
|
||||
furi_assert(status == FuriStatusOk);
|
||||
|
||||
if(event.type == InputTypeShort) {
|
||||
const size_t timer_idx = event.key;
|
||||
furi_assert(timer_idx < TIMER_COUNT);
|
||||
|
||||
FuriEventLoopTimer* timer = app->timers[timer_idx];
|
||||
|
||||
if(furi_event_loop_timer_is_running(timer)) {
|
||||
furi_event_loop_timer_stop(timer);
|
||||
} else {
|
||||
furi_event_loop_timer_restart(timer);
|
||||
}
|
||||
|
||||
} else if(event.type == InputTypeLong) {
|
||||
if(event.key == InputKeyBack) {
|
||||
furi_event_loop_stop(app->event_loop);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void blink_timer_callback(void* context) {
|
||||
const GpioPin* gpio = blink_gpio_pins[(size_t)context];
|
||||
furi_hal_gpio_write(gpio, !furi_hal_gpio_read(gpio));
|
||||
}
|
||||
|
||||
static void event_loop_tick_callback(void* context) {
|
||||
UNUSED(context);
|
||||
furi_hal_gpio_write(&gpio_ext_pc0, !furi_hal_gpio_read(&gpio_ext_pc0));
|
||||
}
|
||||
|
||||
int32_t event_loop_blink_test_app(void* arg) {
|
||||
UNUSED(arg);
|
||||
|
||||
blink_gpio_init();
|
||||
|
||||
EventLoopBlinkTestApp app;
|
||||
|
||||
app.event_loop = furi_event_loop_alloc();
|
||||
app.input_queue = furi_message_queue_alloc(3, sizeof(InputEvent));
|
||||
|
||||
for(size_t i = 0; i < TIMER_COUNT; ++i) {
|
||||
app.timers[i] = furi_event_loop_timer_alloc(
|
||||
app.event_loop, blink_timer_callback, FuriEventLoopTimerTypePeriodic, (void*)i);
|
||||
furi_event_loop_timer_start(app.timers[i], timer_intervals[i]);
|
||||
}
|
||||
|
||||
ViewPort* view_port = view_port_alloc();
|
||||
view_port_draw_callback_set(view_port, view_port_draw_callback, &app);
|
||||
view_port_input_callback_set(view_port, view_port_input_callback, &app);
|
||||
|
||||
Gui* gui = furi_record_open(RECORD_GUI);
|
||||
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
|
||||
|
||||
furi_event_loop_tick_set(app.event_loop, 500, event_loop_tick_callback, &app);
|
||||
furi_event_loop_message_queue_subscribe(
|
||||
app.event_loop, app.input_queue, FuriEventLoopEventIn, input_queue_callback, &app);
|
||||
|
||||
furi_event_loop_run(app.event_loop);
|
||||
|
||||
gui_remove_view_port(gui, view_port);
|
||||
view_port_free(view_port);
|
||||
|
||||
furi_record_close(RECORD_GUI);
|
||||
|
||||
furi_event_loop_message_queue_unsubscribe(app.event_loop, app.input_queue);
|
||||
furi_message_queue_free(app.input_queue);
|
||||
|
||||
for(size_t i = 0; i < TIMER_COUNT; ++i) {
|
||||
furi_event_loop_timer_free(app.timers[i]);
|
||||
}
|
||||
|
||||
furi_event_loop_free(app.event_loop);
|
||||
|
||||
blink_gpio_deinit();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,22 +1,48 @@
|
||||
#include "dolphin.h"
|
||||
#include "helpers/dolphin_state.h"
|
||||
#include "dolphin_i.h"
|
||||
|
||||
#include <furi_hal.h>
|
||||
#include <stdint.h>
|
||||
#include <furi.h>
|
||||
#define DOLPHIN_LOCK_EVENT_FLAG (0x1)
|
||||
|
||||
#define TAG "Dolphin"
|
||||
#define HOURS_IN_TICKS(x) ((x) * 60 * 60 * 1000)
|
||||
|
||||
static void dolphin_update_clear_limits_timer_period(Dolphin* dolphin);
|
||||
#define DOLPHIN_LOCK_EVENT_FLAG (0x1)
|
||||
#define EVENT_QUEUE_SIZE (8)
|
||||
|
||||
#define SECONDS_IN_TICKS(x) ((x) * 1000UL)
|
||||
#define MINUTES_IN_TICKS(x) (SECONDS_IN_TICKS(x) * 60UL)
|
||||
#define HOURS_IN_TICKS(x) (MINUTES_IN_TICKS(x) * 60UL)
|
||||
#define DATE_IN_TICKS(h, m, s) (HOURS_IN_TICKS(h) + MINUTES_IN_TICKS(m) + SECONDS_IN_TICKS(s))
|
||||
|
||||
#define FLUSH_TIMEOUT_TICKS (SECONDS_IN_TICKS(30UL))
|
||||
|
||||
#ifndef DOLPHIN_DEBUG
|
||||
#define BUTTHURT_INCREASE_PERIOD_TICKS (HOURS_IN_TICKS(48UL))
|
||||
#define CLEAR_LIMITS_PERIOD_TICKS (HOURS_IN_TICKS(24UL))
|
||||
#define CLEAR_LIMITS_UPDATE_PERIOD_TICKS (HOURS_IN_TICKS(1UL))
|
||||
#else
|
||||
#define BUTTHURT_INCREASE_PERIOD_TICKS (SECONDS_IN_TICKS(30UL))
|
||||
#define CLEAR_LIMITS_PERIOD_TICKS (MINUTES_IN_TICKS(1))
|
||||
#define CLEAR_LIMITS_UPDATE_PERIOD_TICKS (SECONDS_IN_TICKS(5UL))
|
||||
#endif
|
||||
|
||||
#define CLEAR_LIMITS_UPDATE_THRESHOLD_TICKS (MINUTES_IN_TICKS(5UL))
|
||||
|
||||
#define CLEAR_LIMITS_TIME_HOURS (5UL)
|
||||
#define CLEAR_LIMITS_TIME_TICKS (HOURS_IN_TICKS(CLEAR_LIMITS_TIME_HOURS))
|
||||
|
||||
static void dolphin_event_send_async(Dolphin* dolphin, DolphinEvent* event);
|
||||
static void dolphin_event_send_wait(Dolphin* dolphin, DolphinEvent* event);
|
||||
|
||||
// Public API
|
||||
|
||||
void dolphin_deed(DolphinDeed deed) {
|
||||
Dolphin* dolphin = (Dolphin*)furi_record_open(RECORD_DOLPHIN);
|
||||
Dolphin* dolphin = furi_record_open(RECORD_DOLPHIN);
|
||||
|
||||
DolphinEvent event;
|
||||
event.type = DolphinEventTypeDeed;
|
||||
event.deed = deed;
|
||||
|
||||
dolphin_event_send_async(dolphin, &event);
|
||||
|
||||
furi_record_close(RECORD_DOLPHIN);
|
||||
}
|
||||
|
||||
@@ -43,52 +69,75 @@ void dolphin_flush(Dolphin* dolphin) {
|
||||
dolphin_event_send_wait(dolphin, &event);
|
||||
}
|
||||
|
||||
void dolphin_butthurt_timer_callback(void* context) {
|
||||
Dolphin* dolphin = context;
|
||||
furi_assert(dolphin);
|
||||
void dolphin_upgrade_level(Dolphin* dolphin) {
|
||||
furi_check(dolphin);
|
||||
|
||||
DolphinEvent event;
|
||||
event.type = DolphinEventTypeIncreaseButthurt;
|
||||
event.type = DolphinEventTypeLevel;
|
||||
|
||||
dolphin_event_send_async(dolphin, &event);
|
||||
}
|
||||
|
||||
void dolphin_flush_timer_callback(void* context) {
|
||||
FuriPubSub* dolphin_get_pubsub(Dolphin* dolphin) {
|
||||
furi_check(dolphin);
|
||||
return dolphin->pubsub;
|
||||
}
|
||||
|
||||
// Private functions
|
||||
|
||||
static void dolphin_butthurt_timer_callback(void* context) {
|
||||
Dolphin* dolphin = context;
|
||||
furi_assert(dolphin);
|
||||
|
||||
DolphinEvent event;
|
||||
event.type = DolphinEventTypeFlush;
|
||||
dolphin_event_send_async(dolphin, &event);
|
||||
FURI_LOG_I(TAG, "Increase butthurt");
|
||||
dolphin_state_butthurted(dolphin->state);
|
||||
dolphin_state_save(dolphin->state);
|
||||
}
|
||||
|
||||
void dolphin_clear_limits_timer_callback(void* context) {
|
||||
static void dolphin_flush_timer_callback(void* context) {
|
||||
Dolphin* dolphin = context;
|
||||
furi_assert(dolphin);
|
||||
|
||||
furi_timer_start(dolphin->clear_limits_timer, HOURS_IN_TICKS(24));
|
||||
|
||||
DolphinEvent event;
|
||||
event.type = DolphinEventTypeClearLimits;
|
||||
dolphin_event_send_async(dolphin, &event);
|
||||
FURI_LOG_I(TAG, "Flush stats");
|
||||
dolphin_state_save(dolphin->state);
|
||||
}
|
||||
|
||||
Dolphin* dolphin_alloc(void) {
|
||||
static void dolphin_clear_limits_timer_callback(void* context) {
|
||||
Dolphin* dolphin = context;
|
||||
furi_assert(dolphin);
|
||||
|
||||
FURI_LOG_I(TAG, "Clear limits");
|
||||
dolphin_state_clear_limits(dolphin->state);
|
||||
dolphin_state_save(dolphin->state);
|
||||
}
|
||||
|
||||
static Dolphin* dolphin_alloc(void) {
|
||||
Dolphin* dolphin = malloc(sizeof(Dolphin));
|
||||
|
||||
dolphin->state = dolphin_state_alloc();
|
||||
dolphin->event_queue = furi_message_queue_alloc(8, sizeof(DolphinEvent));
|
||||
dolphin->pubsub = furi_pubsub_alloc();
|
||||
dolphin->butthurt_timer =
|
||||
furi_timer_alloc(dolphin_butthurt_timer_callback, FuriTimerTypePeriodic, dolphin);
|
||||
dolphin->flush_timer =
|
||||
furi_timer_alloc(dolphin_flush_timer_callback, FuriTimerTypeOnce, dolphin);
|
||||
dolphin->clear_limits_timer =
|
||||
furi_timer_alloc(dolphin_clear_limits_timer_callback, FuriTimerTypePeriodic, dolphin);
|
||||
dolphin->event_queue = furi_message_queue_alloc(EVENT_QUEUE_SIZE, sizeof(DolphinEvent));
|
||||
dolphin->event_loop = furi_event_loop_alloc();
|
||||
|
||||
dolphin->butthurt_timer = furi_event_loop_timer_alloc(
|
||||
dolphin->event_loop,
|
||||
dolphin_butthurt_timer_callback,
|
||||
FuriEventLoopTimerTypePeriodic,
|
||||
dolphin);
|
||||
|
||||
dolphin->flush_timer = furi_event_loop_timer_alloc(
|
||||
dolphin->event_loop, dolphin_flush_timer_callback, FuriEventLoopTimerTypeOnce, dolphin);
|
||||
|
||||
dolphin->clear_limits_timer = furi_event_loop_timer_alloc(
|
||||
dolphin->event_loop,
|
||||
dolphin_clear_limits_timer_callback,
|
||||
FuriEventLoopTimerTypePeriodic,
|
||||
dolphin);
|
||||
|
||||
return dolphin;
|
||||
}
|
||||
|
||||
void dolphin_event_send_async(Dolphin* dolphin, DolphinEvent* event) {
|
||||
static void dolphin_event_send_async(Dolphin* dolphin, DolphinEvent* event) {
|
||||
furi_assert(dolphin);
|
||||
furi_assert(event);
|
||||
event->flag = NULL;
|
||||
@@ -96,7 +145,7 @@ void dolphin_event_send_async(Dolphin* dolphin, DolphinEvent* event) {
|
||||
furi_message_queue_put(dolphin->event_queue, event, FuriWaitForever) == FuriStatusOk);
|
||||
}
|
||||
|
||||
void dolphin_event_send_wait(Dolphin* dolphin, DolphinEvent* event) {
|
||||
static void dolphin_event_send_wait(Dolphin* dolphin, DolphinEvent* event) {
|
||||
furi_assert(dolphin);
|
||||
furi_assert(event);
|
||||
|
||||
@@ -110,39 +159,81 @@ void dolphin_event_send_wait(Dolphin* dolphin, DolphinEvent* event) {
|
||||
furi_event_flag_free(event->flag);
|
||||
}
|
||||
|
||||
void dolphin_event_release(Dolphin* dolphin, DolphinEvent* event) {
|
||||
UNUSED(dolphin);
|
||||
static void dolphin_event_release(DolphinEvent* event) {
|
||||
if(event->flag) {
|
||||
furi_event_flag_set(event->flag, DOLPHIN_LOCK_EVENT_FLAG);
|
||||
}
|
||||
}
|
||||
|
||||
FuriPubSub* dolphin_get_pubsub(Dolphin* dolphin) {
|
||||
furi_check(dolphin);
|
||||
return dolphin->pubsub;
|
||||
}
|
||||
static void dolphin_update_clear_limits_timer_period(void* context) {
|
||||
furi_assert(context);
|
||||
Dolphin* dolphin = context;
|
||||
|
||||
static void dolphin_update_clear_limits_timer_period(Dolphin* dolphin) {
|
||||
furi_assert(dolphin);
|
||||
uint32_t now_ticks = furi_get_tick();
|
||||
uint32_t timer_expires_at = furi_timer_get_expire_time(dolphin->clear_limits_timer);
|
||||
uint32_t time_to_clear_limits =
|
||||
furi_event_loop_timer_get_remaining_time(dolphin->clear_limits_timer);
|
||||
|
||||
if((timer_expires_at - now_ticks) > HOURS_IN_TICKS(0.1)) {
|
||||
if(time_to_clear_limits > CLEAR_LIMITS_UPDATE_THRESHOLD_TICKS) {
|
||||
DateTime date;
|
||||
furi_hal_rtc_get_datetime(&date);
|
||||
uint32_t now_time_in_ms = ((date.hour * 60 + date.minute) * 60 + date.second) * 1000;
|
||||
uint32_t time_to_clear_limits = 0;
|
||||
|
||||
if(date.hour < 5) {
|
||||
time_to_clear_limits = HOURS_IN_TICKS(5) - now_time_in_ms;
|
||||
const uint32_t now_time_ticks = DATE_IN_TICKS(date.hour, date.minute, date.second);
|
||||
|
||||
if(date.hour < CLEAR_LIMITS_TIME_HOURS) {
|
||||
time_to_clear_limits = CLEAR_LIMITS_TIME_TICKS - now_time_ticks;
|
||||
} else {
|
||||
time_to_clear_limits = HOURS_IN_TICKS(24 + 5) - now_time_in_ms;
|
||||
time_to_clear_limits =
|
||||
CLEAR_LIMITS_PERIOD_TICKS + CLEAR_LIMITS_TIME_TICKS - now_time_ticks;
|
||||
}
|
||||
|
||||
furi_timer_start(dolphin->clear_limits_timer, time_to_clear_limits);
|
||||
furi_event_loop_timer_start(dolphin->clear_limits_timer, time_to_clear_limits);
|
||||
}
|
||||
|
||||
FURI_LOG_D(TAG, "Daily limits reset in %lu ms", time_to_clear_limits);
|
||||
}
|
||||
|
||||
static bool dolphin_process_event(FuriMessageQueue* queue, void* context) {
|
||||
UNUSED(queue);
|
||||
|
||||
Dolphin* dolphin = context;
|
||||
DolphinEvent event;
|
||||
|
||||
FuriStatus status = furi_message_queue_get(dolphin->event_queue, &event, 0);
|
||||
furi_check(status == FuriStatusOk);
|
||||
|
||||
if(event.type == DolphinEventTypeDeed) {
|
||||
dolphin_state_on_deed(dolphin->state, event.deed);
|
||||
|
||||
DolphinPubsubEvent event = DolphinPubsubEventUpdate;
|
||||
furi_pubsub_publish(dolphin->pubsub, &event);
|
||||
furi_event_loop_timer_start(dolphin->butthurt_timer, BUTTHURT_INCREASE_PERIOD_TICKS);
|
||||
furi_event_loop_timer_start(dolphin->flush_timer, FLUSH_TIMEOUT_TICKS);
|
||||
|
||||
} else if(event.type == DolphinEventTypeStats) {
|
||||
event.stats->icounter = dolphin->state->data.icounter;
|
||||
event.stats->butthurt = dolphin->state->data.butthurt;
|
||||
event.stats->timestamp = dolphin->state->data.timestamp;
|
||||
event.stats->level = dolphin_get_level(dolphin->state->data.icounter);
|
||||
event.stats->level_up_is_pending =
|
||||
!dolphin_state_xp_to_levelup(dolphin->state->data.icounter);
|
||||
|
||||
} else if(event.type == DolphinEventTypeFlush) {
|
||||
furi_event_loop_timer_start(dolphin->flush_timer, FLUSH_TIMEOUT_TICKS);
|
||||
|
||||
} else if(event.type == DolphinEventTypeLevel) {
|
||||
dolphin_state_increase_level(dolphin->state);
|
||||
furi_event_loop_timer_start(dolphin->flush_timer, FLUSH_TIMEOUT_TICKS);
|
||||
|
||||
} else {
|
||||
furi_crash();
|
||||
}
|
||||
|
||||
dolphin_event_release(&event);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Application thread
|
||||
|
||||
int32_t dolphin_srv(void* p) {
|
||||
UNUSED(p);
|
||||
|
||||
@@ -157,54 +248,27 @@ int32_t dolphin_srv(void* p) {
|
||||
furi_record_create(RECORD_DOLPHIN, dolphin);
|
||||
|
||||
dolphin_state_load(dolphin->state);
|
||||
furi_timer_restart(dolphin->butthurt_timer, HOURS_IN_TICKS(2 * 24));
|
||||
dolphin_update_clear_limits_timer_period(dolphin);
|
||||
furi_timer_restart(dolphin->clear_limits_timer, HOURS_IN_TICKS(24));
|
||||
|
||||
DolphinEvent event;
|
||||
while(1) {
|
||||
if(furi_message_queue_get(dolphin->event_queue, &event, HOURS_IN_TICKS(1)) ==
|
||||
FuriStatusOk) {
|
||||
if(event.type == DolphinEventTypeDeed) {
|
||||
dolphin_state_on_deed(dolphin->state, event.deed);
|
||||
DolphinPubsubEvent event = DolphinPubsubEventUpdate;
|
||||
furi_pubsub_publish(dolphin->pubsub, &event);
|
||||
furi_timer_restart(dolphin->butthurt_timer, HOURS_IN_TICKS(2 * 24));
|
||||
furi_timer_restart(dolphin->flush_timer, 30 * 1000);
|
||||
} else if(event.type == DolphinEventTypeStats) {
|
||||
event.stats->icounter = dolphin->state->data.icounter;
|
||||
event.stats->butthurt = dolphin->state->data.butthurt;
|
||||
event.stats->timestamp = dolphin->state->data.timestamp;
|
||||
event.stats->level = dolphin_get_level(dolphin->state->data.icounter);
|
||||
event.stats->level_up_is_pending =
|
||||
!dolphin_state_xp_to_levelup(dolphin->state->data.icounter);
|
||||
} else if(event.type == DolphinEventTypeFlush) {
|
||||
FURI_LOG_I(TAG, "Flush stats");
|
||||
dolphin_state_save(dolphin->state);
|
||||
} else if(event.type == DolphinEventTypeClearLimits) {
|
||||
FURI_LOG_I(TAG, "Clear limits");
|
||||
dolphin_state_clear_limits(dolphin->state);
|
||||
dolphin_state_save(dolphin->state);
|
||||
} else if(event.type == DolphinEventTypeIncreaseButthurt) {
|
||||
FURI_LOG_I(TAG, "Increase butthurt");
|
||||
dolphin_state_butthurted(dolphin->state);
|
||||
dolphin_state_save(dolphin->state);
|
||||
}
|
||||
dolphin_event_release(dolphin, &event);
|
||||
} else {
|
||||
/* once per hour check rtc time is not changed */
|
||||
dolphin_update_clear_limits_timer_period(dolphin);
|
||||
}
|
||||
}
|
||||
furi_event_loop_message_queue_subscribe(
|
||||
dolphin->event_loop,
|
||||
dolphin->event_queue,
|
||||
FuriEventLoopEventIn,
|
||||
dolphin_process_event,
|
||||
dolphin);
|
||||
|
||||
furi_crash("That was unexpected");
|
||||
furi_event_loop_timer_start(dolphin->butthurt_timer, BUTTHURT_INCREASE_PERIOD_TICKS);
|
||||
furi_event_loop_timer_start(dolphin->clear_limits_timer, CLEAR_LIMITS_PERIOD_TICKS);
|
||||
|
||||
furi_event_loop_tick_set(
|
||||
dolphin->event_loop,
|
||||
CLEAR_LIMITS_UPDATE_PERIOD_TICKS,
|
||||
dolphin_update_clear_limits_timer_period,
|
||||
dolphin);
|
||||
|
||||
furi_event_loop_pend_callback(
|
||||
dolphin->event_loop, dolphin_update_clear_limits_timer_period, dolphin);
|
||||
|
||||
furi_event_loop_run(dolphin->event_loop);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dolphin_upgrade_level(Dolphin* dolphin) {
|
||||
furi_check(dolphin);
|
||||
|
||||
dolphin_state_increase_level(dolphin->state);
|
||||
dolphin_flush(dolphin);
|
||||
}
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "helpers/dolphin_deed.h"
|
||||
|
||||
#include <gui/view.h>
|
||||
#include <core/pubsub.h>
|
||||
#include <stdbool.h>
|
||||
#include <core/pubsub.h>
|
||||
|
||||
#include "helpers/dolphin_deed.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <core/pubsub.h>
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
|
||||
#include <core/pubsub.h>
|
||||
|
||||
#include "dolphin.h"
|
||||
#include "helpers/dolphin_state.h"
|
||||
@@ -11,8 +11,7 @@ typedef enum {
|
||||
DolphinEventTypeDeed,
|
||||
DolphinEventTypeStats,
|
||||
DolphinEventTypeFlush,
|
||||
DolphinEventTypeIncreaseButthurt,
|
||||
DolphinEventTypeClearLimits,
|
||||
DolphinEventTypeLevel,
|
||||
} DolphinEventType;
|
||||
|
||||
typedef struct {
|
||||
@@ -25,20 +24,11 @@ typedef struct {
|
||||
} DolphinEvent;
|
||||
|
||||
struct Dolphin {
|
||||
// State
|
||||
DolphinState* state;
|
||||
// Queue
|
||||
FuriMessageQueue* event_queue;
|
||||
FuriPubSub* pubsub;
|
||||
FuriTimer* butthurt_timer;
|
||||
FuriTimer* flush_timer;
|
||||
FuriTimer* clear_limits_timer;
|
||||
FuriMessageQueue* event_queue;
|
||||
FuriEventLoop* event_loop;
|
||||
FuriEventLoopTimer* butthurt_timer;
|
||||
FuriEventLoopTimer* flush_timer;
|
||||
FuriEventLoopTimer* clear_limits_timer;
|
||||
};
|
||||
|
||||
Dolphin* dolphin_alloc(void);
|
||||
|
||||
void dolphin_event_send_async(Dolphin* dolphin, DolphinEvent* event);
|
||||
|
||||
void dolphin_event_send_wait(Dolphin* dolphin, DolphinEvent* event);
|
||||
|
||||
void dolphin_event_release(Dolphin* dolphin, DolphinEvent* event);
|
||||
|
||||
Reference in New Issue
Block a user