diff --git a/zeitraffer.c b/zeitraffer.c index 13198d6dd..b2fd40cfc 100644 --- a/zeitraffer.c +++ b/zeitraffer.c @@ -1,11 +1,17 @@ #include + #include + #include + #include + #include + #include #include "gpio_item.h" + #include "zeitraffer_icons.h" #define CONFIG_FILE_DIRECTORY_PATH "/ext/apps_data/zeitraffer" @@ -24,405 +30,436 @@ int32_t Delay = 3; // Задержка на отскочить bool Work = false; const NotificationSequence sequence_click = { - &message_note_c7, - &message_delay_50, - &message_sound_off, - NULL, + & + message_note_c7, + & + message_delay_50, + & + message_sound_off, + NULL, }; typedef enum { - EventTypeTick, - EventTypeInput, -} EventType; + EventTypeTick, + EventTypeInput, +} +EventType; typedef struct { - EventType type; - InputEvent input; -} ZeitrafferEvent; - -static void draw_callback(Canvas* canvas, void* ctx) { - UNUSED(ctx); - char temp_str[36]; - canvas_clear(canvas); - canvas_set_font(canvas, FontPrimary); - switch (Count) { - case -1: - snprintf(temp_str,sizeof(temp_str),"Set: BULB %li sec",Time); - break; - case 0: - snprintf(temp_str,sizeof(temp_str),"Set: infinite, %li sec",Time); - break; - default: - snprintf(temp_str,sizeof(temp_str),"Set: %li frames, %li sec",Count,Time); - } - canvas_draw_str(canvas, 3, 15, temp_str); - snprintf(temp_str,sizeof(temp_str),"Left: %li frames, %li sec",WorkCount,WorkTime); - canvas_draw_str(canvas, 3, 35, temp_str); - - switch (Backlight) { - case 1: - canvas_draw_str(canvas, 13, 55, "ON"); - break; - case 2: - canvas_draw_str(canvas, 13, 55, "OFF"); - break; - default: - canvas_draw_str(canvas, 13, 55, "AUTO"); - } - - if(Work){ - canvas_draw_icon(canvas, 85, 41, &I_ButtonUpHollow_7x4); - canvas_draw_icon(canvas, 85, 57, &I_ButtonDownHollow_7x4); - canvas_draw_icon(canvas, 59, 48, &I_ButtonLeftHollow_4x7); - canvas_draw_icon(canvas, 72, 48, &I_ButtonRightHollow_4x7); - } - else - { - canvas_draw_icon(canvas, 85, 41, &I_ButtonUp_7x4); - canvas_draw_icon(canvas, 85, 57, &I_ButtonDown_7x4); - canvas_draw_icon(canvas, 59, 48, &I_ButtonLeft_4x7); - canvas_draw_icon(canvas, 72, 48, &I_ButtonRight_4x7); - } - - canvas_draw_icon(canvas, 3, 48, &I_Pin_star_7x7); - - canvas_set_font(canvas, FontPrimary); - canvas_draw_str(canvas, 65, 55, "F"); - - canvas_set_font(canvas, FontPrimary); - canvas_draw_str(canvas, 85, 55, "S"); - - - //canvas_draw_icon(canvas, 59, 48, &I_ButtonLeft_4x7); - //canvas_draw_icon(canvas, 72, 48, &I_ButtonRight_4x7); - - if(Work) {canvas_draw_icon(canvas, 106, 46, &I_loading_10px);} + EventType type; + InputEvent input; +} +ZeitrafferEvent; + +static void draw_callback(Canvas * canvas, void * ctx) { + UNUSED(ctx); + char temp_str[36]; + canvas_clear(canvas); + canvas_set_font(canvas, FontPrimary); + switch (Count) { + case -1: + snprintf(temp_str, sizeof(temp_str), "Set: BULB %li sec", Time); + break; + case 0: + snprintf(temp_str, sizeof(temp_str), "Set: infinite, %li sec", Time); + break; + default: + snprintf(temp_str, sizeof(temp_str), "Set: %li frames, %li sec", Count, Time); + } + canvas_draw_str(canvas, 3, 15, temp_str); + snprintf(temp_str, sizeof(temp_str), "Left: %li frames, %li sec", WorkCount, WorkTime); + canvas_draw_str(canvas, 3, 35, temp_str); + + switch (Backlight) { + case 1: + canvas_draw_str(canvas, 13, 55, "ON"); + break; + case 2: + canvas_draw_str(canvas, 13, 55, "OFF"); + break; + default: + canvas_draw_str(canvas, 13, 55, "AUTO"); + } + + if (Work) { + canvas_draw_icon(canvas, 85, 41, & I_ButtonUpHollow_7x4); + canvas_draw_icon(canvas, 85, 57, & I_ButtonDownHollow_7x4); + canvas_draw_icon(canvas, 59, 48, & I_ButtonLeftHollow_4x7); + canvas_draw_icon(canvas, 72, 48, & I_ButtonRightHollow_4x7); + } else { + canvas_draw_icon(canvas, 85, 41, & I_ButtonUp_7x4); + canvas_draw_icon(canvas, 85, 57, & I_ButtonDown_7x4); + canvas_draw_icon(canvas, 59, 48, & I_ButtonLeft_4x7); + canvas_draw_icon(canvas, 72, 48, & I_ButtonRight_4x7); + } + + canvas_draw_icon(canvas, 3, 48, & I_Pin_star_7x7); + + canvas_set_font(canvas, FontPrimary); + canvas_draw_str(canvas, 65, 55, "F"); + + canvas_set_font(canvas, FontPrimary); + canvas_draw_str(canvas, 85, 55, "S"); + + //canvas_draw_icon(canvas, 59, 48, &I_ButtonLeft_4x7); + //canvas_draw_icon(canvas, 72, 48, &I_ButtonRight_4x7); + + if (Work) { + canvas_draw_icon(canvas, 106, 46, & I_loading_10px); + } } -static void input_callback(InputEvent* input_event, void* ctx) { - // Проверяем, что контекст не нулевой - furi_assert(ctx); - FuriMessageQueue* event_queue = ctx; +static void input_callback(InputEvent * input_event, void * ctx) { + // Проверяем, что контекст не нулевой + furi_assert(ctx); + FuriMessageQueue * event_queue = ctx; - ZeitrafferEvent event = {.type = EventTypeInput, .input = *input_event}; - furi_message_queue_put(event_queue, &event, FuriWaitForever); + ZeitrafferEvent event = { + .type = EventTypeInput, + .input = * input_event + }; + furi_message_queue_put(event_queue, & event, FuriWaitForever); } -static void timer_callback(FuriMessageQueue* event_queue) { - // Проверяем, что контекст не нулевой - furi_assert(event_queue); +static void timer_callback(FuriMessageQueue * event_queue) { + // Проверяем, что контекст не нулевой + furi_assert(event_queue); - ZeitrafferEvent event = {.type = EventTypeTick}; - furi_message_queue_put(event_queue, &event, 0); + ZeitrafferEvent event = { + .type = EventTypeTick + }; + furi_message_queue_put(event_queue, & event, 0); } -int32_t zeitraffer_app(void* p) { - UNUSED(p); - - // Текущее событие типа кастомного типа ZeitrafferEvent - ZeitrafferEvent event; - // Очередь событий на 8 элементов размера ZeitrafferEvent - FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(ZeitrafferEvent)); - - // Создаем новый view port - ViewPort* view_port = view_port_alloc(); - // Создаем callback отрисовки, без контекста - view_port_draw_callback_set(view_port, draw_callback, NULL); - // Создаем callback нажатий на клавиши, в качестве контекста передаем - // нашу очередь сообщений, чтоб запихивать в неё эти события - view_port_input_callback_set(view_port, input_callback, event_queue); - - // Создаем GUI приложения - Gui* gui = furi_record_open(RECORD_GUI); - // Подключаем view port к GUI в полноэкранном режиме - gui_add_view_port(gui, view_port, GuiLayerFullscreen); - - // Конфигурим пины - gpio_item_configure_all_pins(GpioModeOutputPushPull); - - // Создаем периодический таймер с коллбэком, куда в качестве - // контекста будет передаваться наша очередь событий - FuriTimer* timer = furi_timer_alloc(timer_callback, FuriTimerTypePeriodic, event_queue); - // Запускаем таймер - //furi_timer_start(timer, 1500); - - // Включаем нотификации - NotificationApp* notifications = furi_record_open(RECORD_NOTIFICATION); - - - Storage* storage = furi_record_open(RECORD_STORAGE); - - // Загружаем настройки - FlipperFormat* load = flipper_format_file_alloc(storage); - - do { - if(!storage_simply_mkdir(storage, CONFIG_FILE_DIRECTORY_PATH)) {notification_message(notifications, &sequence_error); break;} - if(!flipper_format_file_open_existing(load, CONFIG_FILE_PATH)) {notification_message(notifications, &sequence_error); break;} - if(!flipper_format_read_int32(load, "Time", &Time, 1)) {notification_message(notifications, &sequence_error); break;} - if(!flipper_format_read_int32(load, "Count", &Count, 1)) {notification_message(notifications, &sequence_error); break;} - if(!flipper_format_read_int32(load, "Backlight", &Backlight, 1)) {notification_message(notifications, &sequence_error); break;} - if(!flipper_format_read_int32(load, "Delay", &Delay, 1)) {notification_message(notifications, &sequence_error); break;} - notification_message(notifications, &sequence_success); - - } while(0); - - flipper_format_free(load); - - // Бесконечный цикл обработки очереди событий - while(1) { - // Выбираем событие из очереди в переменную event (ждем бесконечно долго, если очередь пуста) - // и проверяем, что у нас получилось это сделать - furi_check(furi_message_queue_get(event_queue, &event, FuriWaitForever) == FuriStatusOk); - - // Наше событие — это нажатие кнопки - if(event.type == EventTypeInput) { - if(event.input.type == InputTypeShort) { // Короткие нажатия - - if(event.input.key == InputKeyBack) { - if(Work) { // Если таймер запущен - нефиг мацать кнопки! - notification_message(notifications, &sequence_error); - } - else { - WorkCount = Count; - WorkTime = 3; - if (Count == 0) { - InfiniteShot = true; - WorkCount = 1; - } - else - InfiniteShot = false; - - notification_message(notifications, &sequence_success); - } - } - if(event.input.key == InputKeyRight) { - if(furi_timer_is_running(timer)) { - notification_message(notifications, &sequence_error); - } - else { - Count++; - notification_message(notifications, &sequence_click); - } - } - if(event.input.key == InputKeyLeft) { - if(furi_timer_is_running(timer)) { - notification_message(notifications, &sequence_error); - } - else { - Count--; - notification_message(notifications, &sequence_click); - } - } - if(event.input.key == InputKeyUp) { - if(furi_timer_is_running(timer)) { - notification_message(notifications, &sequence_error); - } - else { - Time++; - notification_message(notifications, &sequence_click); - } - } - if(event.input.key == InputKeyDown) { - if(furi_timer_is_running(timer)) { - notification_message(notifications, &sequence_error); - } - else { - Time--; - notification_message(notifications, &sequence_click); - } - } - if(event.input.key == InputKeyOk) { - - if(furi_timer_is_running(timer)) { - notification_message(notifications, &sequence_click); - furi_timer_stop(timer); - Work = false; - } - else { - furi_timer_start(timer, 1000); - Work = true; - - if (WorkCount == 0) - WorkCount = Count; - - if (WorkTime == 0) - WorkTime = Delay; - - if (Count == 1) - WorkTime = Time; - - if (Count == 0) { - InfiniteShot = true; - WorkCount = 1; - } - else - InfiniteShot = false; - - if (Count == -1) { - gpio_item_set_pin(4, true); - gpio_item_set_pin(5, true); - Bulb = true; - WorkCount = 1; - WorkTime = Time; - } - else - Bulb = false; - - notification_message(notifications, &sequence_success); - } - } - } - if(event.input.type == InputTypeLong) { // Длинные нажатия - // Если нажата кнопка "назад", то выходим из цикла, а следовательно и из приложения - if(event.input.key == InputKeyBack) { - if(furi_timer_is_running(timer)) { // А если работает таймер - не выходим :D - notification_message(notifications, &sequence_error); - } - else { - notification_message(notifications, &sequence_click); - gpio_item_set_all_pins(false); - furi_timer_stop(timer); - notification_message(notifications, &sequence_display_backlight_enforce_auto); - break; - } - } - if(event.input.key == InputKeyOk) { - // Нам ваша подсветка и нахой не нужна! Или нужна? - Backlight++; - if (Backlight > 2) Backlight = 0; - } - - } - - if(event.input.type == InputTypeRepeat) { // Зажатые кнопки - if(event.input.key == InputKeyRight) { - if(furi_timer_is_running(timer)) { - notification_message(notifications, &sequence_error); - } - else { - Count = Count+10; - } - } - if(event.input.key == InputKeyLeft) { - if(furi_timer_is_running(timer)) { - notification_message(notifications, &sequence_error); - } - else { - Count = Count-10; - } - } - if(event.input.key == InputKeyUp) { - if(furi_timer_is_running(timer)) { - notification_message(notifications, &sequence_error); - } - else { - Time = Time+10; - } - } - if(event.input.key == InputKeyDown) { - if(furi_timer_is_running(timer)) { - notification_message(notifications, &sequence_error); - } - else { - Time = Time-10; - } - } - } +int32_t zeitraffer_app(void * p) { + UNUSED(p); + + // Текущее событие типа кастомного типа ZeitrafferEvent + ZeitrafferEvent event; + // Очередь событий на 8 элементов размера ZeitrafferEvent + FuriMessageQueue * event_queue = furi_message_queue_alloc(8, sizeof(ZeitrafferEvent)); + + // Создаем новый view port + ViewPort * view_port = view_port_alloc(); + // Создаем callback отрисовки, без контекста + view_port_draw_callback_set(view_port, draw_callback, NULL); + // Создаем callback нажатий на клавиши, в качестве контекста передаем + // нашу очередь сообщений, чтоб запихивать в неё эти события + view_port_input_callback_set(view_port, input_callback, event_queue); + + // Создаем GUI приложения + Gui * gui = furi_record_open(RECORD_GUI); + // Подключаем view port к GUI в полноэкранном режиме + gui_add_view_port(gui, view_port, GuiLayerFullscreen); + + // Конфигурим пины + gpio_item_configure_all_pins(GpioModeOutputPushPull); + + // Создаем периодический таймер с коллбэком, куда в качестве + // контекста будет передаваться наша очередь событий + FuriTimer * timer = furi_timer_alloc(timer_callback, FuriTimerTypePeriodic, event_queue); + // Запускаем таймер + //furi_timer_start(timer, 1500); + + // Включаем нотификации + NotificationApp * notifications = furi_record_open(RECORD_NOTIFICATION); + + Storage * storage = furi_record_open(RECORD_STORAGE); + + // Загружаем настройки + FlipperFormat * load = flipper_format_file_alloc(storage); + + do { + if (!storage_simply_mkdir(storage, CONFIG_FILE_DIRECTORY_PATH)) { + notification_message(notifications, & sequence_error); + break; + } + if (!flipper_format_file_open_existing(load, CONFIG_FILE_PATH)) { + notification_message(notifications, & sequence_error); + break; + } + if (!flipper_format_read_int32(load, "Time", & Time, 1)) { + notification_message(notifications, & sequence_error); + break; + } + if (!flipper_format_read_int32(load, "Count", & Count, 1)) { + notification_message(notifications, & sequence_error); + break; + } + if (!flipper_format_read_int32(load, "Backlight", & Backlight, 1)) { + notification_message(notifications, & sequence_error); + break; + } + if (!flipper_format_read_int32(load, "Delay", & Delay, 1)) { + notification_message(notifications, & sequence_error); + break; + } + notification_message(notifications, & sequence_success); + + } while (0); + + flipper_format_free(load); + + // Бесконечный цикл обработки очереди событий + while (1) { + // Выбираем событие из очереди в переменную event (ждем бесконечно долго, если очередь пуста) + // и проверяем, что у нас получилось это сделать + furi_check(furi_message_queue_get(event_queue, & event, FuriWaitForever) == FuriStatusOk); + + // Наше событие — это нажатие кнопки + if (event.type == EventTypeInput) { + if (event.input.type == InputTypeShort) { // Короткие нажатия + + if (event.input.key == InputKeyBack) { + if (Work) { // Если таймер запущен - нефиг мацать кнопки! + notification_message(notifications, & sequence_error); + } else { + WorkCount = Count; + WorkTime = 3; + if (Count == 0) { + InfiniteShot = true; + WorkCount = 1; + } else + InfiniteShot = false; + + notification_message(notifications, & sequence_success); + } } - - // Наше событие — это сработавший таймер - else if(event.type == EventTypeTick) { - - WorkTime--; - - if( WorkTime < 1 ) { // фоткаем - notification_message(notifications, &sequence_blink_white_100); - if (Bulb) { - gpio_item_set_all_pins(false); WorkCount = 0; - } - else { - WorkCount--; - view_port_update(view_port); - notification_message(notifications, &sequence_click); - // Дрыгаем ногами - //gpio_item_set_all_pins(true); - gpio_item_set_pin(4, true); - gpio_item_set_pin(5, true); - furi_delay_ms(400); // На короткие нажатия фотик плохо реагирует - gpio_item_set_pin(4, false); - gpio_item_set_pin(5, false); - //gpio_item_set_all_pins(false); - - if (InfiniteShot) WorkCount++; - - WorkTime = Time; - view_port_update(view_port); - } - } - else { - // Отправляем нотификацию мигания синим светодиодом - notification_message(notifications, &sequence_blink_blue_100); - } - - if( WorkCount < 1 ) { // закончили - Work = false; - gpio_item_set_all_pins(false); - furi_timer_stop(timer); - notification_message(notifications, &sequence_audiovisual_alert); - WorkTime = 3; - WorkCount = 0; - } - - switch (Backlight) { // чо по подсветке? - case 1: - notification_message(notifications, &sequence_display_backlight_on); - break; - case 2: - notification_message(notifications, &sequence_display_backlight_off); - break; - default: - notification_message(notifications, &sequence_display_backlight_enforce_auto); - } - + if (event.input.key == InputKeyRight) { + if (furi_timer_is_running(timer)) { + notification_message(notifications, & sequence_error); + } else { + Count++; + notification_message(notifications, & sequence_click); + } + } + if (event.input.key == InputKeyLeft) { + if (furi_timer_is_running(timer)) { + notification_message(notifications, & sequence_error); + } else { + Count--; + notification_message(notifications, & sequence_click); + } + } + if (event.input.key == InputKeyUp) { + if (furi_timer_is_running(timer)) { + notification_message(notifications, & sequence_error); + } else { + Time++; + notification_message(notifications, & sequence_click); + } + } + if (event.input.key == InputKeyDown) { + if (furi_timer_is_running(timer)) { + notification_message(notifications, & sequence_error); + } else { + Time--; + notification_message(notifications, & sequence_click); + } + } + if (event.input.key == InputKeyOk) { + + if (furi_timer_is_running(timer)) { + notification_message(notifications, & sequence_click); + furi_timer_stop(timer); + Work = false; + } else { + furi_timer_start(timer, 1000); + Work = true; + + if (WorkCount == 0) + WorkCount = Count; + + if (WorkTime == 0) + WorkTime = Delay; + + if (Count == 1) + WorkTime = Time; + + if (Count == 0) { + InfiniteShot = true; + WorkCount = 1; + } else + InfiniteShot = false; + + if (Count == -1) { + gpio_item_set_pin(4, true); + gpio_item_set_pin(5, true); + Bulb = true; + WorkCount = 1; + WorkTime = Time; + } else + Bulb = false; + + notification_message(notifications, & sequence_success); + } + } + } + if (event.input.type == InputTypeLong) { // Длинные нажатия + // Если нажата кнопка "назад", то выходим из цикла, а следовательно и из приложения + if (event.input.key == InputKeyBack) { + if (furi_timer_is_running(timer)) { // А если работает таймер - не выходим :D + notification_message(notifications, & sequence_error); + } else { + notification_message(notifications, & sequence_click); + gpio_item_set_all_pins(false); + furi_timer_stop(timer); + notification_message(notifications, & sequence_display_backlight_enforce_auto); + break; + } + } + if (event.input.key == InputKeyOk) { + // Нам ваша подсветка и нахой не нужна! Или нужна? + Backlight++; + if (Backlight > 2) Backlight = 0; } - if (Time < 1) Time = 1; // Не даём открутить таймер меньше единицы - if (Count < -1) Count = 0; // А тут даём, бо 0 кадров это бесконечная съёмка, а -1 кадров - BULB - } - - - // Схороняем настройки - FlipperFormat* save = flipper_format_file_alloc(storage); - - do { - - if(!flipper_format_file_open_always(save, CONFIG_FILE_PATH)) {notification_message(notifications, &sequence_error); break;} - if(!flipper_format_write_header_cstr(save, "Zeitraffer", 1)) {notification_message(notifications, &sequence_error); break;} - if(!flipper_format_write_comment_cstr(save, "Zeitraffer app settings: № of frames, interval time, backlight type, Delay")) {notification_message(notifications, &sequence_error); break;} - if(!flipper_format_write_int32(save, "Time", &Time, 1)) {notification_message(notifications, &sequence_error); break;} - if(!flipper_format_write_int32(save, "Count", &Count, 1)) {notification_message(notifications, &sequence_error); break;} - if(!flipper_format_write_int32(save, "Backlight", &Backlight, 1)) {notification_message(notifications, &sequence_error); break;} - if(!flipper_format_write_int32(save, "Delay", &Delay, 1)) {notification_message(notifications, &sequence_error); break;} - - } while(0); - - flipper_format_free(save); - - furi_record_close(RECORD_STORAGE); - - // Очищаем таймер - furi_timer_free(timer); - - // Специальная очистка памяти, занимаемой очередью - furi_message_queue_free(event_queue); - - // Чистим созданные объекты, связанные с интерфейсом - gui_remove_view_port(gui, view_port); - view_port_free(view_port); - furi_record_close(RECORD_GUI); - // Очищаем нотификации - furi_record_close(RECORD_NOTIFICATION); + } - return 0; -} + if (event.input.type == InputTypeRepeat) { // Зажатые кнопки + if (event.input.key == InputKeyRight) { + if (furi_timer_is_running(timer)) { + notification_message(notifications, & sequence_error); + } else { + Count = Count + 10; + } + } + if (event.input.key == InputKeyLeft) { + if (furi_timer_is_running(timer)) { + notification_message(notifications, & sequence_error); + } else { + Count = Count - 10; + } + } + if (event.input.key == InputKeyUp) { + if (furi_timer_is_running(timer)) { + notification_message(notifications, & sequence_error); + } else { + Time = Time + 10; + } + } + if (event.input.key == InputKeyDown) { + if (furi_timer_is_running(timer)) { + notification_message(notifications, & sequence_error); + } else { + Time = Time - 10; + } + } + } + } + + // Наше событие — это сработавший таймер + else if (event.type == EventTypeTick) { + + WorkTime--; + + if (WorkTime < 1) { // фоткаем + notification_message(notifications, & sequence_blink_white_100); + if (Bulb) { + gpio_item_set_all_pins(false); + WorkCount = 0; + } else { + WorkCount--; + view_port_update(view_port); + notification_message(notifications, & sequence_click); + // Дрыгаем ногами + //gpio_item_set_all_pins(true); + gpio_item_set_pin(4, true); + gpio_item_set_pin(5, true); + furi_delay_ms(400); // На короткие нажатия фотик плохо реагирует + gpio_item_set_pin(4, false); + gpio_item_set_pin(5, false); + //gpio_item_set_all_pins(false); + + if (InfiniteShot) WorkCount++; + + WorkTime = Time; + view_port_update(view_port); + } + } else { + // Отправляем нотификацию мигания синим светодиодом + notification_message(notifications, & sequence_blink_blue_100); + } + + if (WorkCount < 1) { // закончили + Work = false; + gpio_item_set_all_pins(false); + furi_timer_stop(timer); + notification_message(notifications, & sequence_audiovisual_alert); + WorkTime = 3; + WorkCount = 0; + } + + switch (Backlight) { // чо по подсветке? + case 1: + notification_message(notifications, & sequence_display_backlight_on); + break; + case 2: + notification_message(notifications, & sequence_display_backlight_off); + break; + default: + notification_message(notifications, & sequence_display_backlight_enforce_auto); + } + + } + if (Time < 1) Time = 1; // Не даём открутить таймер меньше единицы + if (Count < -1) Count = 0; // А тут даём, бо 0 кадров это бесконечная съёмка, а -1 кадров - BULB + } + + // Схороняем настройки + FlipperFormat * save = flipper_format_file_alloc(storage); + + do { + + if (!flipper_format_file_open_always(save, CONFIG_FILE_PATH)) { + notification_message(notifications, & sequence_error); + break; + } + if (!flipper_format_write_header_cstr(save, "Zeitraffer", 1)) { + notification_message(notifications, & sequence_error); + break; + } + if (!flipper_format_write_comment_cstr(save, "Zeitraffer app settings: № of frames, interval time, backlight type, Delay")) { + notification_message(notifications, & sequence_error); + break; + } + if (!flipper_format_write_int32(save, "Time", & Time, 1)) { + notification_message(notifications, & sequence_error); + break; + } + if (!flipper_format_write_int32(save, "Count", & Count, 1)) { + notification_message(notifications, & sequence_error); + break; + } + if (!flipper_format_write_int32(save, "Backlight", & Backlight, 1)) { + notification_message(notifications, & sequence_error); + break; + } + if (!flipper_format_write_int32(save, "Delay", & Delay, 1)) { + notification_message(notifications, & sequence_error); + break; + } + + } while (0); + + flipper_format_free(save); + + furi_record_close(RECORD_STORAGE); + + // Очищаем таймер + furi_timer_free(timer); + + // Специальная очистка памяти, занимаемой очередью + furi_message_queue_free(event_queue); + + // Чистим созданные объекты, связанные с интерфейсом + gui_remove_view_port(gui, view_port); + view_port_free(view_port); + furi_record_close(RECORD_GUI); + + // Очищаем нотификации + furi_record_close(RECORD_NOTIFICATION); + + return 0; +} \ No newline at end of file