diff --git a/applications/desktop/desktop_i.h b/applications/desktop/desktop_i.h index c23ab41b..62caff0f 100644 --- a/applications/desktop/desktop_i.h +++ b/applications/desktop/desktop_i.h @@ -19,7 +19,7 @@ #include "views/desktop_debug.h" #include "scenes/desktop_scene.h" - +#include "helpers/desktop_animation.h" #include "desktop/desktop_settings/desktop_settings.h" typedef enum { diff --git a/applications/desktop/helpers/desktop_animation.c b/applications/desktop/helpers/desktop_animation.c new file mode 100644 index 00000000..07eaf631 --- /dev/null +++ b/applications/desktop/helpers/desktop_animation.c @@ -0,0 +1,26 @@ +#include "desktop_animation.h" + +static const Icon* idle_scenes[] = {&A_Wink_128x64, &A_WatchingTV_128x64}; + +const Icon* desktop_get_icon() { + uint8_t new = 0; + +#if 0 + // checking dolphin state here to choose appropriate animation + + Dolphin* dolphin = furi_record_open("dolphin"); + DolphinStats stats = dolphin_stats(dolphin); + float timediff = fabs(difftime(stats.timestamp, dolphin_state_timestamp())); + + FURI_LOG_I("desktop-animation", "background change"); + FURI_LOG_I("desktop-animation", "icounter: %d", stats.icounter); + FURI_LOG_I("desktop-animation", "butthurt: %d", stats.butthurt); + FURI_LOG_I("desktop-animation", "time since deeed: %.0f", timediff); +#endif + + if((random() % 100) > 50) { // temp rnd selection + new = random() % COUNT_OF(idle_scenes); + } + + return idle_scenes[new]; +} diff --git a/applications/desktop/helpers/desktop_animation.h b/applications/desktop/helpers/desktop_animation.h new file mode 100644 index 00000000..10ad906f --- /dev/null +++ b/applications/desktop/helpers/desktop_animation.h @@ -0,0 +1,10 @@ +#pragma once + +#include +#include +#include +#include "dolphin/dolphin.h" +#include "dolphin/helpers/dolphin_state.h" +#include "time.h" + +const Icon* desktop_get_icon(); diff --git a/applications/desktop/scenes/desktop_scene_locked.c b/applications/desktop/scenes/desktop_scene_locked.c index fd7a96b6..6e7064ad 100644 --- a/applications/desktop/scenes/desktop_scene_locked.c +++ b/applications/desktop/scenes/desktop_scene_locked.c @@ -13,6 +13,7 @@ void desktop_scene_locked_on_enter(void* context) { desktop_locked_set_callback(locked_view, desktop_scene_locked_callback, desktop); desktop_locked_reset_door_pos(locked_view); desktop_locked_update_hint_timeout(locked_view); + desktop_locked_set_dolphin_animation(locked_view); view_port_enabled_set(desktop->lock_viewport, true); osTimerStart(locked_view->timer, 63); diff --git a/applications/desktop/scenes/desktop_scene_main.c b/applications/desktop/scenes/desktop_scene_main.c index fab3a91e..4826c2cd 100644 --- a/applications/desktop/scenes/desktop_scene_main.c +++ b/applications/desktop/scenes/desktop_scene_main.c @@ -39,6 +39,7 @@ void desktop_scene_main_on_enter(void* context) { desktop_main_unlocked(desktop->main_view); } + desktop_main_switch_dolphin_animation(desktop->main_view); view_dispatcher_switch_to_view(desktop->view_dispatcher, DesktopViewMain); } diff --git a/applications/desktop/views/desktop_debug.c b/applications/desktop/views/desktop_debug.c index 55259917..067fd478 100644 --- a/applications/desktop/views/desktop_debug.c +++ b/applications/desktop/views/desktop_debug.c @@ -2,8 +2,8 @@ #include "../desktop_i.h" #include "desktop_debug.h" -#include "applications/dolphin/helpers/dolphin_state.h" -#include "applications/dolphin/dolphin.h" +#include "dolphin/helpers/dolphin_state.h" +#include "dolphin/dolphin.h" void desktop_debug_set_callback( DesktopDebugView* debug_view, @@ -21,7 +21,7 @@ void desktop_debug_render(Canvas* canvas, void* model) { const Version* ver; char buffer[64]; - static const char* headers[] = {"FW Version info:", "Boot Version info:", "Desktop info:"}; + static const char* headers[] = {"FW Version info:", "Boot Version info:", "Dolphin info:"}; canvas_set_color(canvas, ColorBlack); canvas_set_font(canvas, FontPrimary); @@ -56,7 +56,7 @@ void desktop_debug_render(Canvas* canvas, void* model) { "%s [%s]", version_get_version(ver), version_get_builddate(ver)); - canvas_draw_str(canvas, 5, 33, buffer); + canvas_draw_str(canvas, 5, 32, buffer); snprintf( buffer, @@ -68,16 +68,22 @@ void desktop_debug_render(Canvas* canvas, void* model) { snprintf( buffer, sizeof(buffer), "[%s] %s", version_get_target(ver), version_get_gitbranch(ver)); - canvas_draw_str(canvas, 5, 53, buffer); + canvas_draw_str(canvas, 5, 54, buffer); } else { char buffer[64]; + uint32_t current_lvl = dolphin_state_get_level(m->icounter); + uint32_t remaining = dolphin_state_xp_to_levelup(m->icounter, current_lvl, true); canvas_set_font(canvas, FontSecondary); - snprintf(buffer, 64, "Icounter: %ld", m->icounter); - canvas_draw_str(canvas, 5, 30, buffer); - snprintf(buffer, 64, "Butthurt: %ld", m->butthurt); - canvas_draw_str(canvas, 5, 40, buffer); + snprintf(buffer, 64, "Icounter: %ld Butthurt %ld", m->icounter, m->butthurt); + canvas_draw_str(canvas, 5, 23, buffer); + + snprintf(buffer, 64, "Level: %ld To level up: %ld", current_lvl, remaining); + canvas_draw_str(canvas, 5, 33, buffer); + + snprintf(buffer, 64, "%s", asctime(localtime((const time_t*)&m->timestamp))); + canvas_draw_str(canvas, 5, 43, buffer); canvas_draw_str(canvas, 0, 53, "[< >] icounter value [ok] save"); } } @@ -151,6 +157,7 @@ void desktop_debug_get_dolphin_data(DesktopDebugView* debug_view) { debug_view->view, (DesktopDebugViewModel * model) { model->icounter = stats.icounter; model->butthurt = stats.butthurt; + model->timestamp = stats.timestamp; return true; }); diff --git a/applications/desktop/views/desktop_debug.h b/applications/desktop/views/desktop_debug.h index 02ce76a2..b3ff67fc 100644 --- a/applications/desktop/views/desktop_debug.h +++ b/applications/desktop/views/desktop_debug.h @@ -6,6 +6,7 @@ #include #include #include +#include typedef enum { DesktopDebugEventDeed, @@ -35,6 +36,7 @@ struct DesktopDebugView { typedef struct { uint32_t icounter; uint32_t butthurt; + uint64_t timestamp; DesktopViewStatsScreens screen; } DesktopDebugViewModel; diff --git a/applications/desktop/views/desktop_locked.c b/applications/desktop/views/desktop_locked.c index 42b286f7..b4942506 100644 --- a/applications/desktop/views/desktop_locked.c +++ b/applications/desktop/views/desktop_locked.c @@ -2,8 +2,6 @@ #include "../desktop_i.h" #include "desktop_locked.h" -static const Icon* idle_scenes[] = {&A_Wink_128x64, &A_WatchingTV_128x64}; - void desktop_locked_set_callback( DesktopLockedView* locked_view, DesktopLockedViewCallback callback, @@ -20,11 +18,11 @@ void locked_view_timer_callback(void* context) { } // temporary locked screen animation managment -static void desktop_locked_set_scene(DesktopLockedView* locked_view, const Icon* icon_data) { +void desktop_locked_set_dolphin_animation(DesktopLockedView* locked_view) { with_view_model( locked_view->view, (DesktopLockedViewModel * model) { if(model->animation) icon_animation_free(model->animation); - model->animation = icon_animation_alloc(icon_data); + model->animation = icon_animation_alloc(desktop_get_icon()); view_tie_icon_animation(locked_view->view, model->animation); return true; }); @@ -42,8 +40,8 @@ void desktop_locked_reset_door_pos(DesktopLockedView* locked_view) { with_view_model( locked_view->view, (DesktopLockedViewModel * model) { model->animation_seq_end = false; - model->door_left_x = -57; - model->door_right_x = 115; + model->door_left_x = DOOR_L_POS; + model->door_right_x = DOOR_R_POS; return true; }); } @@ -57,10 +55,10 @@ void desktop_locked_manage_redraw(DesktopLockedView* locked_view) { animation_seq_end = model->animation_seq_end; if(!model->animation_seq_end) { - model->door_left_x = CLAMP(model->door_left_x + 5, 0, -57); - model->door_right_x = CLAMP(model->door_right_x - 5, 115, 60); + model->door_left_x = CLAMP(model->door_left_x + 5, DOOR_L_POS_MAX, DOOR_L_POS); + model->door_right_x = CLAMP(model->door_right_x - 5, DOOR_R_POS, DOOR_R_POS_MIN); } else { - model->hint_expire_at = 0; + model->hint_expire_at = !model->hint_expire_at; } return true; @@ -84,7 +82,7 @@ void desktop_locked_reset_counter(DesktopLockedView* locked_view) { void desktop_locked_render(Canvas* canvas, void* model) { DesktopLockedViewModel* m = model; - + uint32_t now = osKernelGetTickCount(); canvas_clear(canvas); canvas_set_color(canvas, ColorBlack); @@ -97,7 +95,7 @@ void desktop_locked_render(Canvas* canvas, void* model) { canvas_draw_icon_animation(canvas, 0, -3, m->animation); } - if(osKernelGetTickCount() < m->hint_expire_at) { + if(now < m->hint_expire_at) { if(!m->animation_seq_end) { canvas_set_font(canvas, FontPrimary); elements_multiline_text_framed(canvas, 42, 30, "Locked"); @@ -125,7 +123,6 @@ bool desktop_locked_input(InputEvent* event, void* context) { if(event->key == InputKeyBack) { uint32_t press_time = osKernelGetTickCount(); - // check if pressed sequentially if(press_time - locked_view->lock_lastpress > UNLOCK_RST_TIMEOUT) { locked_view->lock_lastpress = press_time; @@ -178,7 +175,6 @@ DesktopLockedView* desktop_locked_alloc() { view_set_enter_callback(locked_view->view, desktop_locked_enter); view_set_exit_callback(locked_view->view, desktop_locked_exit); - desktop_locked_set_scene(locked_view, idle_scenes[random() % COUNT_OF(idle_scenes)]); return locked_view; } diff --git a/applications/desktop/views/desktop_locked.h b/applications/desktop/views/desktop_locked.h index bf83dce5..c85705a8 100644 --- a/applications/desktop/views/desktop_locked.h +++ b/applications/desktop/views/desktop_locked.h @@ -9,6 +9,11 @@ #define UNLOCK_RST_TIMEOUT 300 #define UNLOCK_CNT 2 // 3 actually +#define DOOR_L_POS -57 +#define DOOR_L_POS_MAX 0 +#define DOOR_R_POS 115 +#define DOOR_R_POS_MIN 60 + typedef enum { DesktopLockedEventUnlock, DesktopLockedEventUpdate, @@ -44,6 +49,7 @@ void desktop_locked_set_callback( DesktopLockedViewCallback callback, void* context); +void desktop_locked_set_dolphin_animation(DesktopLockedView* locked_view); void desktop_locked_update_hint_timeout(DesktopLockedView* locked_view); void desktop_locked_reset_counter(DesktopLockedView* locked_view); void desktop_locked_reset_door_pos(DesktopLockedView* locked_view); diff --git a/applications/desktop/views/desktop_main.c b/applications/desktop/views/desktop_main.c index 72af9a1c..a35ba008 100644 --- a/applications/desktop/views/desktop_main.c +++ b/applications/desktop/views/desktop_main.c @@ -2,8 +2,6 @@ #include "../desktop_i.h" #include "desktop_main.h" -static const Icon* idle_scenes[] = {&A_Wink_128x64, &A_WatchingTV_128x64}; - void desktop_main_set_callback( DesktopMainView* main_view, DesktopMainViewCallback callback, @@ -22,38 +20,26 @@ void desktop_main_reset_hint(DesktopMainView* main_view) { }); } -// temporary main screen animation managment -static void desktop_main_set_scene(DesktopMainView* main_view, const Icon* icon_data) { +void desktop_main_switch_dolphin_animation(DesktopMainView* main_view) { with_view_model( main_view->view, (DesktopMainViewModel * model) { if(model->animation) icon_animation_free(model->animation); - model->animation = icon_animation_alloc(icon_data); + model->animation = icon_animation_alloc(desktop_get_icon()); view_tie_icon_animation(main_view->view, model->animation); return true; }); } -void desktop_scene_handler_switch_scene(DesktopMainView* main_view) { - with_view_model( - main_view->view, (DesktopMainViewModel * model) { - if(icon_animation_is_last_frame(model->animation)) { - if(model->animation) icon_animation_free(model->animation); - model->animation = icon_animation_alloc(idle_scenes[model->scene_num]); - model->scene_num = random() % COUNT_OF(idle_scenes); - } - return true; - }); -} - void desktop_main_render(Canvas* canvas, void* model) { canvas_clear(canvas); DesktopMainViewModel* m = model; + uint32_t now = osKernelGetTickCount(); if(m->animation) { canvas_draw_icon_animation(canvas, 0, -3, m->animation); } - if(osKernelGetTickCount() < m->hint_expire_at) { + if(now < m->hint_expire_at) { canvas_set_font(canvas, FontPrimary); elements_multiline_text_framed(canvas, 42, 30, "Unlocked"); } @@ -115,8 +101,6 @@ DesktopMainView* desktop_main_alloc() { view_set_enter_callback(main_view->view, desktop_main_enter); view_set_exit_callback(main_view->view, desktop_main_exit); - desktop_main_set_scene(main_view, idle_scenes[random() % COUNT_OF(idle_scenes)]); - return main_view; } diff --git a/applications/desktop/views/desktop_main.h b/applications/desktop/views/desktop_main.h index e723078c..78678b8c 100644 --- a/applications/desktop/views/desktop_main.h +++ b/applications/desktop/views/desktop_main.h @@ -41,3 +41,5 @@ View* desktop_main_get_view(DesktopMainView* main_view); DesktopMainView* desktop_main_alloc(); void desktop_main_free(DesktopMainView* main_view); + +void desktop_main_switch_dolphin_animation(DesktopMainView* main_view); diff --git a/applications/dolphin/dolphin.c b/applications/dolphin/dolphin.c index b30fe0d6..f1f1e5e5 100644 --- a/applications/dolphin/dolphin.c +++ b/applications/dolphin/dolphin.c @@ -1,6 +1,6 @@ #include "dolphin_i.h" #include - +#define DOLPHIN_TIMEGATE 86400 // one day #define DOLPHIN_LOCK_EVENT_FLAG (0x1) void dolphin_deed(Dolphin* dolphin, DolphinDeed deed) { @@ -77,6 +77,21 @@ void dolphin_event_release(Dolphin* dolphin, DolphinEvent* event) { } } +static void dolphin_check_butthurt(DolphinState* state) { + furi_assert(state); + float diff_time = difftime(dolphin_state_get_timestamp(state), dolphin_state_timestamp()); + +#if 0 + FURI_LOG_I("dolphin-state", "Butthurt check, time since deed %.0f", fabs(diff_time)); +#endif + + if((fabs(diff_time)) > DOLPHIN_TIMEGATE) { + // increase butthurt + FURI_LOG_I("dolphin-state", "Increasing butthurt"); + dolphin_state_butthurted(state); + } +} + int32_t dolphin_srv(void* p) { Dolphin* dolphin = dolphin_alloc(); furi_record_create("dolphin", dolphin); @@ -91,11 +106,13 @@ int32_t dolphin_srv(void* p) { } else if(event.type == DolphinEventTypeStats) { event.stats->icounter = dolphin_state_get_icounter(dolphin->state); event.stats->butthurt = dolphin_state_get_butthurt(dolphin->state); + event.stats->timestamp = dolphin_state_get_timestamp(dolphin->state); } else if(event.type == DolphinEventTypeFlush) { dolphin_state_save(dolphin->state); } dolphin_event_release(dolphin, &event); } else { + dolphin_check_butthurt(dolphin->state); dolphin_state_save(dolphin->state); } } diff --git a/applications/dolphin/dolphin.h b/applications/dolphin/dolphin.h index e0ac9307..c8edca61 100644 --- a/applications/dolphin/dolphin.h +++ b/applications/dolphin/dolphin.h @@ -7,6 +7,7 @@ typedef struct Dolphin Dolphin; typedef struct { uint32_t icounter; uint32_t butthurt; + uint64_t timestamp; } DolphinStats; /** Deed complete notification. Call it on deed completion. diff --git a/applications/dolphin/helpers/dolphin_state.c b/applications/dolphin/helpers/dolphin_state.c index a525f442..240b7d95 100644 --- a/applications/dolphin/helpers/dolphin_state.c +++ b/applications/dolphin/helpers/dolphin_state.c @@ -25,6 +25,7 @@ typedef struct { uint32_t flags; uint32_t icounter; uint32_t butthurt; + uint64_t timestamp; } DolphinStoreData; typedef struct { @@ -107,8 +108,12 @@ bool dolphin_state_load(DolphinState* dolphin_state) { File* file = storage_file_alloc(dolphin_state->fs_api); bool load_result = storage_file_open(file, DOLPHIN_STORE_KEY, FSAM_READ, FSOM_OPEN_EXISTING); - - if(load_result) { + if(!load_result) { + FURI_LOG_E( + "dolphin-state", + "Load failed. Storage returned: %s", + storage_file_get_error_desc(file)); + } else { uint16_t bytes_count = storage_file_read(file, &store, sizeof(DolphinStore)); if(bytes_count != sizeof(DolphinStore)) { @@ -117,12 +122,8 @@ bool dolphin_state_load(DolphinState* dolphin_state) { } if(!load_result) { - FURI_LOG_E( - "dolphin-state", - "Load failed. Storage returned: %s", - storage_file_get_error_desc(file)); + FURI_LOG_E("dolphin-state", "DolphinStore size mismatch"); } else { - FURI_LOG_I("dolphin-state", "State loaded, verifying header"); if(store.header.magic == DOLPHIN_STORE_HEADER_MAGIC && store.header.version == DOLPHIN_STORE_HEADER_VERSION) { FURI_LOG_I( @@ -150,7 +151,7 @@ bool dolphin_state_load(DolphinState* dolphin_state) { } else { FURI_LOG_E( "dolphin-state", - "Magic(%d != %d) and Version(%d != %d) mismatch", + "Magic(%d != %d) or Version(%d != %d) mismatch", store.header.magic, DOLPHIN_STORE_HEADER_MAGIC, store.header.version, @@ -171,17 +172,45 @@ void dolphin_state_clear(DolphinState* dolphin_state) { memset(&dolphin_state->data, 0, sizeof(DolphinStoreData)); } +uint64_t dolphin_state_timestamp() { + RTC_TimeTypeDef time; + RTC_DateTypeDef date; + struct tm current; + + HAL_RTC_GetTime(&hrtc, &time, RTC_FORMAT_BIN); + HAL_RTC_GetDate(&hrtc, &date, RTC_FORMAT_BIN); + + current.tm_year = date.Year + 100; + current.tm_mday = date.Date; + current.tm_mon = date.Month - 1; + + current.tm_hour = time.Hours; + current.tm_min = time.Minutes; + current.tm_sec = time.Seconds; + + return mktime(¤t); +} + void dolphin_state_on_deed(DolphinState* dolphin_state, DolphinDeed deed) { const DolphinDeedWeight* deed_weight = dolphin_deed_weight(deed); int32_t icounter = dolphin_state->data.icounter + deed_weight->icounter; + int32_t butthurt = dolphin_state->data.butthurt; if(icounter >= 0) { dolphin_state->data.icounter = icounter; + dolphin_state->data.butthurt = MAX(butthurt - deed_weight->icounter, 0); + dolphin_state->data.timestamp = dolphin_state_timestamp(); } dolphin_state->dirty = true; } +void dolphin_state_butthurted(DolphinState* dolphin_state) { + dolphin_state->data.butthurt++; + dolphin_state->data.timestamp = dolphin_state_timestamp(); + dolphin_state->dirty = true; +} + uint32_t dolphin_state_get_icounter(DolphinState* dolphin_state) { return dolphin_state->data.icounter; } @@ -190,13 +219,14 @@ uint32_t dolphin_state_get_butthurt(DolphinState* dolphin_state) { return dolphin_state->data.butthurt; } -uint32_t dolphin_state_get_level(DolphinState* dolphin_state) { - return 0.5f + - sqrtf(1.0f + 8.0f * ((float)dolphin_state->data.icounter / DOLPHIN_LVL_THRESHOLD)) / - 2.0f; +uint64_t dolphin_state_get_timestamp(DolphinState* dolphin_state) { + return dolphin_state->data.timestamp; } -uint32_t dolphin_state_xp_to_levelup(DolphinState* dolphin_state, uint32_t level, bool remaining) { - return (DOLPHIN_LVL_THRESHOLD * level * (level + 1) / 2) - - (remaining ? dolphin_state->data.icounter : 0); +uint32_t dolphin_state_get_level(uint32_t icounter) { + return 0.5f + sqrtf(1.0f + 8.0f * ((float)icounter / DOLPHIN_LVL_THRESHOLD)) / 2.0f; +} + +uint32_t dolphin_state_xp_to_levelup(uint32_t icounter, uint32_t level, bool remaining) { + return (DOLPHIN_LVL_THRESHOLD * level * (level + 1) / 2) - (remaining ? icounter : 0); } \ No newline at end of file diff --git a/applications/dolphin/helpers/dolphin_state.h b/applications/dolphin/helpers/dolphin_state.h index cbd9611a..7c4a33cd 100644 --- a/applications/dolphin/helpers/dolphin_state.h +++ b/applications/dolphin/helpers/dolphin_state.h @@ -3,6 +3,8 @@ #include "dolphin_deed.h" #include #include +#include +#include typedef struct DolphinState DolphinState; @@ -16,12 +18,18 @@ bool dolphin_state_load(DolphinState* dolphin_state); void dolphin_state_clear(DolphinState* dolphin_state); +uint64_t dolphin_state_timestamp(); + void dolphin_state_on_deed(DolphinState* dolphin_state, DolphinDeed deed); +void dolphin_state_butthurted(DolphinState* dolphin_state); + uint32_t dolphin_state_get_icounter(DolphinState* dolphin_state); uint32_t dolphin_state_get_butthurt(DolphinState* dolphin_state); -uint32_t dolphin_state_get_level(DolphinState* dolphin_state); +uint64_t dolphin_state_get_timestamp(DolphinState* dolphin_state); -uint32_t dolphin_state_xp_to_levelup(DolphinState* dolphin_state, uint32_t level, bool remaining); \ No newline at end of file +uint32_t dolphin_state_get_level(uint32_t icounter); + +uint32_t dolphin_state_xp_to_levelup(uint32_t icounter, uint32_t level, bool remaining); \ No newline at end of file