Dolphin_srv: fix state load on startup (#731)
* Dolphin_srv: fix dolphin state load on startup * Dolphin: new sync and async API, state autosave. Makefile: properly escaped asterisks. Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
This commit is contained in:
		| @@ -2,8 +2,8 @@ APP_DIR		= $(PROJECT_ROOT)/applications | |||||||
| LIB_DIR		= $(PROJECT_ROOT)/lib | LIB_DIR		= $(PROJECT_ROOT)/lib | ||||||
|  |  | ||||||
| CFLAGS		+= -I$(APP_DIR) | CFLAGS		+= -I$(APP_DIR) | ||||||
| C_SOURCES	+= $(shell find $(APP_DIR) -name *.c) | C_SOURCES	+= $(shell find $(APP_DIR) -name "*.c") | ||||||
| CPP_SOURCES	+= $(shell find $(APP_DIR) -name *.cpp) | CPP_SOURCES	+= $(shell find $(APP_DIR) -name "*.cpp") | ||||||
|  |  | ||||||
|  |  | ||||||
| APP_RELEASE ?= 1 | APP_RELEASE ?= 1 | ||||||
|   | |||||||
| @@ -26,7 +26,7 @@ bool desktop_scene_debug_on_event(void* context, SceneManagerEvent event) { | |||||||
|         switch(event.event) { |         switch(event.event) { | ||||||
|         case DesktopDebugEventExit: |         case DesktopDebugEventExit: | ||||||
|             scene_manager_next_scene(desktop->scene_manager, DesktopSceneMain); |             scene_manager_next_scene(desktop->scene_manager, DesktopSceneMain); | ||||||
|             dolphin_save(dolphin); |             dolphin_flush(dolphin); | ||||||
|             consumed = true; |             consumed = true; | ||||||
|             break; |             break; | ||||||
|  |  | ||||||
| @@ -43,7 +43,7 @@ bool desktop_scene_debug_on_event(void* context, SceneManagerEvent event) { | |||||||
|             break; |             break; | ||||||
|  |  | ||||||
|         case DesktopDebugEventSaveState: |         case DesktopDebugEventSaveState: | ||||||
|             dolphin_save(dolphin); |             dolphin_flush(dolphin); | ||||||
|             consumed = true; |             consumed = true; | ||||||
|             break; |             break; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -146,7 +146,7 @@ void desktop_debug_free(DesktopDebugView* debug_view) { | |||||||
|  |  | ||||||
| void desktop_debug_get_dolphin_data(DesktopDebugView* debug_view) { | void desktop_debug_get_dolphin_data(DesktopDebugView* debug_view) { | ||||||
|     Dolphin* dolphin = furi_record_open("dolphin"); |     Dolphin* dolphin = furi_record_open("dolphin"); | ||||||
|     DolphinDeedWeight stats = dolphin_stats(dolphin); |     DolphinStats stats = dolphin_stats(dolphin); | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         debug_view->view, (DesktopDebugViewModel * model) { |         debug_view->view, (DesktopDebugViewModel * model) { | ||||||
|             model->icounter = stats.icounter; |             model->icounter = stats.icounter; | ||||||
|   | |||||||
| @@ -1,34 +1,39 @@ | |||||||
| #include "dolphin_i.h" | #include "dolphin_i.h" | ||||||
| #include <furi.h> | #include <furi.h> | ||||||
|  |  | ||||||
| bool dolphin_load(Dolphin* dolphin) { | #define DOLPHIN_LOCK_EVENT_FLAG (0x1) | ||||||
|     furi_assert(dolphin); |  | ||||||
|     return dolphin_state_load(dolphin->state); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void dolphin_save(Dolphin* dolphin) { |  | ||||||
|     furi_assert(dolphin); |  | ||||||
|     DolphinEvent event; |  | ||||||
|     event.type = DolphinEventTypeSave; |  | ||||||
|     furi_check(osMessageQueuePut(dolphin->event_queue, &event, 0, osWaitForever) == osOK); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void dolphin_deed(Dolphin* dolphin, DolphinDeed deed) { | void dolphin_deed(Dolphin* dolphin, DolphinDeed deed) { | ||||||
|     furi_assert(dolphin); |     furi_assert(dolphin); | ||||||
|     DolphinEvent event; |     DolphinEvent event; | ||||||
|     event.type = DolphinEventTypeDeed; |     event.type = DolphinEventTypeDeed; | ||||||
|     event.deed = deed; |     event.deed = deed; | ||||||
|     furi_check(osMessageQueuePut(dolphin->event_queue, &event, 0, osWaitForever) == osOK); |     dolphin_event_send_async(dolphin, &event); | ||||||
| } | } | ||||||
|  |  | ||||||
| DolphinDeedWeight dolphin_stats(Dolphin* dolphin) { | DolphinStats dolphin_stats(Dolphin* dolphin) { | ||||||
|     DolphinDeedWeight stats; |     furi_assert(dolphin); | ||||||
|     stats.butthurt = dolphin_state_get_butthurt(dolphin->state); |  | ||||||
|     stats.icounter = dolphin_state_get_icounter(dolphin->state); |     DolphinStats stats; | ||||||
|  |     DolphinEvent event; | ||||||
|  |  | ||||||
|  |     event.type = DolphinEventTypeStats; | ||||||
|  |     event.stats = &stats; | ||||||
|  |  | ||||||
|  |     dolphin_event_send_wait(dolphin, &event); | ||||||
|  |  | ||||||
|     return stats; |     return stats; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | void dolphin_flush(Dolphin* dolphin) { | ||||||
|  |     furi_assert(dolphin); | ||||||
|  |  | ||||||
|  |     DolphinEvent event; | ||||||
|  |     event.type = DolphinEventTypeFlush; | ||||||
|  |  | ||||||
|  |     dolphin_event_send_wait(dolphin, &event); | ||||||
|  | } | ||||||
|  |  | ||||||
| Dolphin* dolphin_alloc() { | Dolphin* dolphin_alloc() { | ||||||
|     Dolphin* dolphin = furi_alloc(sizeof(Dolphin)); |     Dolphin* dolphin = furi_alloc(sizeof(Dolphin)); | ||||||
|  |  | ||||||
| @@ -47,27 +52,55 @@ void dolphin_free(Dolphin* dolphin) { | |||||||
|     free(dolphin); |     free(dolphin); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | void dolphin_event_send_async(Dolphin* dolphin, DolphinEvent* event) { | ||||||
|  |     furi_assert(dolphin); | ||||||
|  |     furi_assert(event); | ||||||
|  |     event->flag = NULL; | ||||||
|  |     furi_check(osMessageQueuePut(dolphin->event_queue, event, 0, osWaitForever) == osOK); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void dolphin_event_send_wait(Dolphin* dolphin, DolphinEvent* event) { | ||||||
|  |     furi_assert(dolphin); | ||||||
|  |     furi_assert(event); | ||||||
|  |     event->flag = osEventFlagsNew(NULL); | ||||||
|  |     furi_check(event->flag); | ||||||
|  |     furi_check(osMessageQueuePut(dolphin->event_queue, event, 0, osWaitForever) == osOK); | ||||||
|  |     furi_check( | ||||||
|  |         osEventFlagsWait(event->flag, DOLPHIN_LOCK_EVENT_FLAG, osFlagsWaitAny, osWaitForever) == | ||||||
|  |         DOLPHIN_LOCK_EVENT_FLAG); | ||||||
|  |     furi_check(osEventFlagsDelete(event->flag) == osOK); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void dolphin_event_release(Dolphin* dolphin, DolphinEvent* event) { | ||||||
|  |     if(event->flag) { | ||||||
|  |         osEventFlagsSet(event->flag, DOLPHIN_LOCK_EVENT_FLAG); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
| int32_t dolphin_srv(void* p) { | int32_t dolphin_srv(void* p) { | ||||||
|     Dolphin* dolphin = dolphin_alloc(); |     Dolphin* dolphin = dolphin_alloc(); | ||||||
|     furi_record_create("dolphin", dolphin); |     furi_record_create("dolphin", dolphin); | ||||||
|  |  | ||||||
|  |     dolphin_state_load(dolphin->state); | ||||||
|  |  | ||||||
|     DolphinEvent event; |     DolphinEvent event; | ||||||
|     while(1) { |     while(1) { | ||||||
|         furi_check(osMessageQueueGet(dolphin->event_queue, &event, NULL, osWaitForever) == osOK); |         if(osMessageQueueGet(dolphin->event_queue, &event, NULL, 60000) == osOK) { | ||||||
|         switch(event.type) { |             if(event.type == DolphinEventTypeDeed) { | ||||||
|         case DolphinEventTypeDeed: |                 dolphin_state_on_deed(dolphin->state, event.deed); | ||||||
|             dolphin_state_on_deed(dolphin->state, event.deed); |             } else if(event.type == DolphinEventTypeStats) { | ||||||
|             break; |                 event.stats->icounter = dolphin_state_get_icounter(dolphin->state); | ||||||
|  |                 event.stats->butthurt = dolphin_state_get_butthurt(dolphin->state); | ||||||
|         case DolphinEventTypeSave: |             } else if(event.type == DolphinEventTypeFlush) { | ||||||
|  |                 dolphin_state_save(dolphin->state); | ||||||
|  |             } | ||||||
|  |             dolphin_event_release(dolphin, &event); | ||||||
|  |         } else { | ||||||
|             dolphin_state_save(dolphin->state); |             dolphin_state_save(dolphin->state); | ||||||
|             break; |  | ||||||
|  |  | ||||||
|         default: |  | ||||||
|             break; |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     dolphin_free(dolphin); |     dolphin_free(dolphin); | ||||||
|  |  | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -4,27 +4,23 @@ | |||||||
|  |  | ||||||
| typedef struct Dolphin Dolphin; | typedef struct Dolphin Dolphin; | ||||||
|  |  | ||||||
| /* Load Dolphin state | typedef struct { | ||||||
|  * Thread safe |     uint32_t icounter; | ||||||
|  */ |     uint32_t butthurt; | ||||||
|  | } DolphinStats; | ||||||
|  |  | ||||||
| bool dolphin_load(Dolphin* dolphin); | /** Deed complete notification. Call it on deed completion. | ||||||
|  |  | ||||||
| /* Deed complete notification. Call it on deed completion. |  | ||||||
|  * See dolphin_deed.h for available deeds. In futures it will become part of assets. |  * See dolphin_deed.h for available deeds. In futures it will become part of assets. | ||||||
|  * Thread safe |  * Thread safe, async | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
| void dolphin_deed(Dolphin* dolphin, DolphinDeed deed); | void dolphin_deed(Dolphin* dolphin, DolphinDeed deed); | ||||||
|  |  | ||||||
| /* Save Dolphin state (write to permanent memory) | /** Retrieve dolphin stats | ||||||
|  * Thread safe |  * Thread safe, blocking | ||||||
|  */ |  */ | ||||||
|  | DolphinStats dolphin_stats(Dolphin* dolphin); | ||||||
|  |  | ||||||
| void dolphin_save(Dolphin* dolphin); | /** Flush dolphin queue and save state | ||||||
|  |  * Thread safe, blocking | ||||||
| /* Retrieve dolphin's icounter and butthurt values |  | ||||||
|  * Thread safe |  | ||||||
|  */ |  */ | ||||||
|  | void dolphin_flush(Dolphin* dolphin); | ||||||
| DolphinDeedWeight dolphin_stats(Dolphin* dolphin); |  | ||||||
| @@ -8,14 +8,16 @@ | |||||||
|  |  | ||||||
| typedef enum { | typedef enum { | ||||||
|     DolphinEventTypeDeed, |     DolphinEventTypeDeed, | ||||||
|     DolphinEventTypeSave, |     DolphinEventTypeStats, | ||||||
|     DolphinEventTypeTick, |     DolphinEventTypeFlush, | ||||||
| } DolphinEventType; | } DolphinEventType; | ||||||
|  |  | ||||||
| typedef struct { | typedef struct { | ||||||
|     DolphinEventType type; |     DolphinEventType type; | ||||||
|  |     osEventFlagsId_t flag; | ||||||
|     union { |     union { | ||||||
|         DolphinDeed deed; |         DolphinDeed deed; | ||||||
|  |         DolphinStats* stats; | ||||||
|     }; |     }; | ||||||
| } DolphinEvent; | } DolphinEvent; | ||||||
|  |  | ||||||
| @@ -29,3 +31,9 @@ struct Dolphin { | |||||||
| Dolphin* dolphin_alloc(); | Dolphin* dolphin_alloc(); | ||||||
|  |  | ||||||
| void dolphin_free(Dolphin* dolphin); | void dolphin_free(Dolphin* dolphin); | ||||||
|  |  | ||||||
|  | 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); | ||||||
|   | |||||||
| @@ -35,6 +35,7 @@ typedef struct { | |||||||
| struct DolphinState { | struct DolphinState { | ||||||
|     Storage* fs_api; |     Storage* fs_api; | ||||||
|     DolphinStoreData data; |     DolphinStoreData data; | ||||||
|  |     bool dirty; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| DolphinState* dolphin_state_alloc() { | DolphinState* dolphin_state_alloc() { | ||||||
| @@ -49,8 +50,12 @@ void dolphin_state_free(DolphinState* dolphin_state) { | |||||||
| } | } | ||||||
|  |  | ||||||
| bool dolphin_state_save(DolphinState* dolphin_state) { | bool dolphin_state_save(DolphinState* dolphin_state) { | ||||||
|  |     if(!dolphin_state->dirty) { | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     FURI_LOG_I("dolphin-state", "State is dirty, saving to \"%s\"", DOLPHIN_STORE_KEY); | ||||||
|     DolphinStore store; |     DolphinStore store; | ||||||
|     FURI_LOG_I("dolphin-state", "Saving state to \"%s\"", DOLPHIN_STORE_KEY); |  | ||||||
|     // Calculate checksum |     // Calculate checksum | ||||||
|     uint8_t* source = (uint8_t*)&dolphin_state->data; |     uint8_t* source = (uint8_t*)&dolphin_state->data; | ||||||
|     uint8_t checksum = 0; |     uint8_t checksum = 0; | ||||||
| @@ -88,7 +93,10 @@ bool dolphin_state_save(DolphinState* dolphin_state) { | |||||||
|     storage_file_close(file); |     storage_file_close(file); | ||||||
|     storage_file_free(file); |     storage_file_free(file); | ||||||
|  |  | ||||||
|  |     dolphin_state->dirty = !save_result; | ||||||
|  |  | ||||||
|     FURI_LOG_I("dolphin-state", "Saved"); |     FURI_LOG_I("dolphin-state", "Saved"); | ||||||
|  |  | ||||||
|     return save_result; |     return save_result; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -153,6 +161,9 @@ bool dolphin_state_load(DolphinState* dolphin_state) { | |||||||
|  |  | ||||||
|     storage_file_close(file); |     storage_file_close(file); | ||||||
|     storage_file_free(file); |     storage_file_free(file); | ||||||
|  |  | ||||||
|  |     dolphin_state->dirty = !load_result; | ||||||
|  |  | ||||||
|     return load_result; |     return load_result; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -167,6 +178,8 @@ void dolphin_state_on_deed(DolphinState* dolphin_state, DolphinDeed deed) { | |||||||
|     if(icounter >= 0) { |     if(icounter >= 0) { | ||||||
|         dolphin_state->data.icounter = icounter; |         dolphin_state->data.icounter = icounter; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     dolphin_state->dirty = true; | ||||||
| } | } | ||||||
|  |  | ||||||
| uint32_t dolphin_state_get_icounter(DolphinState* dolphin_state) { | uint32_t dolphin_state_get_icounter(DolphinState* dolphin_state) { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user